Cross-Origin Resource Sharing with Spring Security

后端 未结 8 1557
暖寄归人
暖寄归人 2020-12-01 04:39

I\'m trying to make CORS play nicely with Spring Security but it\'s not complying. I made the changes described in this article and changing this line in applicationCo

相关标签:
8条回答
  • 2020-12-01 05:13

    Since Spring Security 4.1, this is the proper way to make Spring Security support CORS (also needed in Spring Boot 1.4/1.5):

    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
        }
    }
    

    and:

    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    //        http.csrf().disable();
            http.cors();
        }
    
        @Bean
        public CorsConfigurationSource corsConfigurationSource() {
            final CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedOrigins(ImmutableList.of("*"));
            configuration.setAllowedMethods(ImmutableList.of("HEAD",
                    "GET", "POST", "PUT", "DELETE", "PATCH"));
            // setAllowCredentials(true) is important, otherwise:
            // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
            configuration.setAllowCredentials(true);
            // setAllowedHeaders is important! Without it, OPTIONS preflight request
            // will fail with 403 Invalid CORS request
            configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
            final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
            return source;
        }
    }
    

    Do not do any of below, which are the wrong way to attempt solving the problem:

    • http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
    • web.ignoring().antMatchers(HttpMethod.OPTIONS);

    Reference: http://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html

    0 讨论(0)
  • 2020-12-01 05:15

    I totally agree with the answer given by Bludream, but I have some remarks:

    I would extend the if clause in the CORS filter with a NULL check on the origin header:

    public class CorsFilter extends OncePerRequestFilter {
    
        private static final String ORIGIN = "Origin";
    
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
    
            if (request.getHeader(ORIGIN) == null || request.getHeader(ORIGIN).equals("null")) {
                response.addHeader("Access-Control-Allow-Origin", "*");
                response.setHeader("Access-Control-Allow-Credentials", "true");
                response.addHeader("Access-Control-Max-Age", "10");
    
                String reqHead = request.getHeader("Access-Control-Request-Headers");
    
                if (!StringUtils.isEmpty(reqHead)) {
                    response.addHeader("Access-Control-Allow-Headers", reqHead);
                }
            }
            if (request.getMethod().equals("OPTIONS")) {
                try {
                    response.getWriter().print("OK");
                    response.getWriter().flush();
                } catch (IOException e) {
                e.printStackTrace();
                }
            } else{
                filterChain.doFilter(request, response);
            }
        }
     }
    

    Furthermore, I noticed the following unwanted behavior: If I try to access a REST API with an unauthorized role, Spring security returns me an HTTP status 403: FORBIDDEN and the CORS headers are returned. However, if I use an unknown token, or a token that isn't valid anymore, an HTTP status 401: UNAUTHORIZED is returned WITHOUT CORS headers.

    I managed to make it work by changing the filter configuration in the security XML like this:

    <security:http use-expressions="true" .... >
        ...
        //your other configs
        <sec:custom-filter ref="corsFilter" before="HEADERS_FILTER"/>
    </security:http>
    

    And the following bean for our custom filter:

    <bean id="corsFilter" class="<<location of the CORS filter class>>" />
    
    0 讨论(0)
提交回复
热议问题