简体   繁体   中英

Spring Security Logout doesn't work with Spring 4 CORS

Recently I tried the new built-in CORS-Support in Spring 4 . This feature is great and I want to implement this in my Spring Boot / AngularJS application.

All request works fine but I can't logout my user because the OPTIONS -Request to /logout is handled by Spring Security .

Is it possible to handle the OPTIONS -Request before Spring Security or should I attach CORS-Headers in LogoutSuccessHandler ?

When working with Spring Security, it is recommended to use CorsFilter . You will want to ensure that you order the CorsFilter before Spring Security's FilterChainProxy .

You can refer to Spring Data Rest and Cors for details on using CorsFilter . For this issue, the difference is likely that you want to register only for the logout URL. For example:

@Bean
public CorsFilter corsFilter() {

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true); // you USUALLY want this
    // likely you should limit this to specific origins
    config.addAllowedOrigin("*"); 
    config.addAllowedHeader("*");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("PUT");
    source.registerCorsConfiguration("/logout", config);
    return new CorsFilter(source);
}

I know this is a bit late. I was having the same problem with /logout being rejected by my Angular2 browser app because of the CORS header Access-Control-Allow-Origin not being returned in the /logout response. The /logout seems to be processed before the CORS filter is reached so doesn't get the header. I tried the solution above but it didn't work for me. So, i tried this next solution and it works great:

  • Create a LogoutHandler implementation class and implement logout()
  • Create a LogoutSuccessHandler implementation class and implement onLogoutSuccess()
  • Wire the two classes to the Spring security configuration

Turns out I didn't need the LogoutSuccessHandler class, just the LogoutHandler. The LogoutSuccessHandler (not shown) is just an empty implementation with a logging statement in it. The LogoutHandler is below. This is a snippet of a Spring-boot REST app coded in Groovy (very similar to java)

@Slf4j
class TodosLogoutHandler implements LogoutHandler {

/**
 * For some reason the spring-session logout gets processed before the request
 * reaches the CORS filter so the response doesn't get the allow-origin header
 * which then causes the browser to reject the logout response. I tried a bunch
 * of other methods of trying to include /logout to the CORS filter but they
 * didn't work so figured a logout handler would be a place I could manually
 * set the header to persuade the browser to accept the response - it worked!!
 * @param request
 * @param response
 * @param authentication
 */
  @Override
  void logout(
        HttpServletRequest request,
        HttpServletResponse response,
        Authentication authentication) {

    response.setHeader("Access-Control-Allow-Origin", "*")

    log.info("TodosLogoutHandler logging you out of the back-end app.")
  }
}

Then wire this together in your security configuration class that extends WebSecurityConfigurerAdapter like this below. The last part, showing the logout section is the relevant part in the standard configure() method.

    @Override
  public void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()                 // Allow any CORS OPTIONS calls
            .antMatchers(HttpMethod.GET, "/priority", "/status").permitAll()    // Allow all ref data
            .anyRequest().authenticated()
            .and()
                .csrf().disable()
                .httpBasic().realmName("Spring REST Todos")
            .and()
                // Custom logout handler only exists to handle a CORS problem with /logout
                // where spring-session processes the logout request/response before it gets
                // to the CORS filter so it doesn't get the allow-origin header which  then
                // causes the browser to reject the /logout response. Manually set the
                // allow-origin header in the logout handler and Bob's your uncle.
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new TodosLogoutSuccessHandler())
                .addLogoutHandler(new TodosLogoutHandler())
                .invalidateHttpSession(true)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM