首页 文章

Spring安全登录页面与SPA中的React Router重定向

提问于
浏览
0

我遇到配置问题,当在开发模式下运行时,Spring Security会重定向到我的React前端的登录页面(与React Router一起运行) . 我相信重定向不会被我的前端接收,这是由于我对服务器端路由如何与SPA路由交互的理解 .

我的开发前端Web服务器(使用Facebook Create React App)在localhost:3000上运行,我的后端Spring Boot Tomcat在localhost:8080上运行 . 我启用了Spring Security,它在Tomcat服务器上工作正常(端口8080);访问localhost:8080转发到localhost:8080 / login . 访问localhost:3000时,我遇到了跨源错误,因此在Spring中添加了CORS支持,如here所述 . 我也咨询过this Spring 季博客文章 . 它似乎有效,因为我不再得到跨源错误 . 但是,在未登录的情况下,localhost:3000到localhost:8080 / login的请求将返回以下内容:

HTTP/1.1 200 OK
X-Powered-By: Express
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=UTF-8
Content-Length: 1496
ETag: W/"5d8-80rXYG+kNfQ/xEJ7J2f1PA"
Vary: Accept-Encoding
Date: Tue, 10 Jan 2017 12:04:07 GMT
Connection: keep-alive

<!DOCTYPE html>
...

这是我的前端网络服务器中托管的index.html . 这很好,但我需要它转发到localhost:3000 / login,这会将登录页面呈现为index.html .

我相信它不会转发到/ login因为路由设置,它来自 localhost:3000/ - > HttpSecurity.loginPage("/login") (Spring) - > registry.addViewController("/login").setViewName("forward:/index.html") (Spring) - > <Route path="/" component={ForwardToLandingPage} /> (React Router)

最后它出了问题 . 我希望Tomcat服务器将前端重定向到:3000 / login,而前端则转到组件 . 似乎服务器端重定向和前端React Router到达正确位置之间存在问题 . 如果这太复杂而无法设置,我可能会将整个Spring Security放在我的开发环境中 .

这是我的配置:

React routing config

ReactDOM.render((
    <Router history={browserHistory}>
        <Route path="/" component={ForwardToLandingPage} />
        <Route path="/login" component={Login} />
    </Router>
    ),
    document.getElementById('root')
);

Spring MVC config

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {          
        // This forwarding is required, as my React app is rendering on a div
        // element with the ID 'root' in /index.html. But is this part of the
        // problem?
        registry.addViewController("/").setViewName("forward:/index.html");
        registry.addViewController("/login").setViewName("forward:/index.html");
    }
}

Spring CORS config

@Configuration
public class MyConfiguration {

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:3000");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }
}

Spring Security config

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable() // temporary fix
                .authorizeRequests()
                    .antMatchers("/h2-console", "/public/**", "/static/**").permitAll()
                    .anyRequest().authenticated()
                    .and()
                .formLogin()
                    .loginPage("/login")
                    .permitAll()
                    .and()
                .logout()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
    }
}

有什么想法会出错吗?

我想知道问题的解决方案是否应该涉及Tomcat,所以也检查了this .

谢谢你的帮助! :)

1 回答

  • -1

    我们使用的是旧版本的Spring安全性,我不知道它是否支持CORS . 我使用Spring安全性已有6年了,所以我只创建了一个常规过滤器:

    public class CORSFilter implements Filter {
    
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) res;
            HttpServletRequest httpServletRequest = (HttpServletRequest) req;
            // The headers needs to be on all responses.
            String origin = httpServletRequest.getHeader("origin");
            if (origin == null) {
                // Make the developers life simpler. The browser adds the origin but it is a pain to
                // for developers to add this header while testing.
                origin = "*";
            }
            response.setHeader("Access-Control-Allow-Origin", origin.replace("\n", ""));
    
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Accept, Authorization");
    
            // For options requests return immediately. Options does not require authentication so we want to return
            // here to avoid all yet unknown security risks.
            if (HttpMethod.OPTIONS.toString().equals(httpServletRequest.getMethod())) {
                return;
            }
            chain.doFilter(req, res);
        }
    
        public void init(FilterConfig filterConfig) {
        }
    
        public void destroy() {
        }
    }
    

    并在ChannelProcessingFilter之前添加,因此它成为过滤器链中的第一个过滤器 .

    http.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class);
     http.formLogin().....
    // all the other matchers and
    

    如果这对您不起作用,那么我不确定它只是一个CORS问题 .

相关问题