I’m having a configuration problem with Spring Security re-directing to a login page on my React front end (running with React Router) when running in development mode. I believe the redirect isn't being picked up by my front end, and is due to my noob understanding of how server side routing interacts with SPA routing.
My development front end web server (using Facebook Create React App) is running on localhost:3000, my backend Spring Boot Tomcat on localhost:8080. I’ve enabled Spring Security, which works fine on the Tomcat server (port 8080); accessing localhost:8080 forwards to localhost:8080/login. When accessing localhost:3000, I got a cross-origin error, so added CORS support in Spring as described here. I also consulted this Spring blog post. It seems to work, in that I no longer get the cross-origin error. However, while not logged in, the request from localhost:3000 to localhost:8080/login returns the following:
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>
...
This is the index.html hosted in my front end webserver. This is good, but I need it to forward to localhost:3000/login, which will render the login page into index.html.
I believe it's not forwarding to /login because of the routing setup, it goes from localhost:3000/ -> HttpSecurity.loginPage("/login") (Spring) -> registry.addViewController("/login").setViewName("forward:/index.html") (Spring) -> <Route path="/" component={ForwardToLandingPage} /> (React Router)
It goes wrong at the end. I want the Tomcat server to re-direct the front end to :3000/login, but instead the front end goes to the component. Seems there's a problem between the server side redirect and the front end React Router going to the right place. If this is too complex to set up, I might just drop this whole Spring Security in my development environment.
Here are my configurations:
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"));
}
}
Any ideas what's going wrong?
I was wondering if the solution to the problem should involve Tomcat, so checked this too.
Thanks for any help! :)