1
votes

I am building an app with Spring-boot (on http://localhost:8080) and angular (on http://localhost:80).

the frontend and backend code are served by 2 different servers. In order to avoid CORS problems, I used to put in place an intermediate nginx server but I am not satisfied with this solution anymore. Hence, I have to allow CORS.

I allowed CORS globally with those lines :

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {   

  @Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
        .allowedOrigins("http://localhost")
        .allowCredentials(true)
    ;
  }
}

This works for every routes except for the authentication route which is handled with Spring security :

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Override
  public void configure(HttpSecurity http) throws Exception {
    http
      .formLogin()
      .successHandler(successHandler())
      .failureHandler(failureHandler())
    //[...]
  }

  private AuthenticationSuccessHandler successHandler() {
    return (httpServletRequest, httpServletResponse, authentication) ->
      httpServletResponse.setStatus(HttpServletResponse.SC_OK);
  }

  private AuthenticationFailureHandler failureHandler() {
    return (httpServletRequest, httpServletResponse, e) -> {
       httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    };
}

Here is the code that sends the request on the frontend part :

$http.post('http://localhost:8080/api/login', $.param({'username': username, 'password': password}),
            {headers: {'content-type': 'application/x-www-form-urlencoded'}}
).then(function() {})
.catch(function(error) {};

If I enter the correct password, the http response code (that I can see in the Chrome console) is 200 but I still reach the catch block (with error.status = -1) and I can see this error message in the console :

XMLHttpRequest cannot load http://localhost:8080/api/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

If I enter the wrong password I also reach the catch block with this error message :

XMLHttpRequest cannot load http://localhost:8080/api/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. The response had HTTP status code 401.

I also notice that CORS response headers are missing when I call the authentication endpoint.

Any ideas?

EDIT : it works if I manually add headers in the custom success handler. I would prefer if Spring-security could take into account the global CORS configuration.

3

3 Answers

0
votes

From my experience you'll need to include the port number in CORS, the error message from the browser is a bit misleading.

You can verify that by inspecting network and check the Origin field of your request headers. The value in Access-Control-Allow-Origin of your response headers must match that exactly including protocol and port.

0
votes

You should take a look on Spring website. There are solutions for consuming web service and managing CORS :

0
votes

Had the exact same issue two thing you could do,

  1. @CrossOrigin(origins = "http://localhost:8080") add this to the service methods. The idea behind this is you enable CORS request through your service itself.
  2. Use JSONP, but this has certain limitation. Also i wasnt successful in implementing it, so i used the above option.