弹簧安全CORS过滤器编辑 1:

我们添加到现有项目中。Spring Security

从这一刻起,我们从服务器收到401错误。No 'Access-Control-Allow-Origin' header is present on the requested resource

这是因为没有标头附加到响应。为了解决这个问题,我们添加了我们自己的过滤器,该过滤器位于注销过滤器之前的链中,但过滤器不适用于我们的请求。Access-Control-Allow-OriginFilter

我们的错误:

XMLHttpRequest 无法加载 。请求的资源上不存在“访问控制-允许-源”标头。因此,不允许访问源。响应具有 HTTP 状态代码 401。http://localhost:8080/getKundenhttp://localhost:3000

我们的安全配置:

@EnableWebSecurity
@Configuration
@ComponentScan("com.company.praktikant")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private MyFilter filter;

@Override
public void configure(HttpSecurity http) throws Exception {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();

    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("POST");
    source.registerCorsConfiguration("/**", config);
    http.addFilterBefore(new MyFilter(), LogoutFilter.class).authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/*").permitAll();
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
}
}

我们的过滤器

@Component
public class MyFilter extends OncePerRequestFilter {

@Override
public void destroy() {

}

private String getAllowedDomainsRegex() {
    return "individual / customized Regex";
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    final String origin = "http://localhost:3000";

    response.addHeader("Access-Control-Allow-Origin", origin);
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    response.setHeader("Access-Control-Allow-Credentials", "true");
    response.setHeader("Access-Control-Allow-Headers",
            "content-type, x-gwt-module-base, x-gwt-permutation, clientid, longpush");

    filterChain.doFilter(request, response);

}
}

我们的应用

@SpringBootApplication
public class Application {
public static void main(String[] args) {
    final ApplicationContext ctx = SpringApplication.run(Application.class, args);
    final AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
    annotationConfigApplicationContext.register(CORSConfig.class);
    annotationConfigApplicationContext.refresh();
}
}

我们的过滤器从弹簧启动注册:

2016-11-04 09:19:51.494 INFO 9704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'myFilter' to: [/*]

我们生成的过滤链:

2016-11-04 09:19:52.729 INFO 9704 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain : 创建过滤器链: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5d8c5a8a, org.springframework.security.web.context.SecurityContextPersistenceFilter@7d6938f, org.springframework.security.web.header.HeaderWriterFilter@72aa89c,org.springframework.security.web.csrf.CsrfFilter@4af4df11、com.company.praktikant.MyFilter@5ba65db2、org.springframework.security.web.authentication.logout.LogoutFilter@2330834f、org.springframework.security.web.savedrequest.RequestCacheAwareFilter@396532d1、org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@4fc0f1a2、org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2357120f、org.springframework.security.web.session.SessionManagementFilter@10867bfb、org.springframework.security.web.access.ExceptionTranslationFilter@4b8bf1fb org.springframework.security.web.access.intercept.FilterSecurityInterceptor@42063cf1]

响应:响应标头

我们也尝试了春季的解决方案,但它不起作用!我们控制器中的注释@CrossOrigin也没有帮助。

编辑 1:

尝试了@Piotr Sołtysiak的解决方案。cors 筛选器未在生成的筛选器链中列出,我们仍然会收到相同的错误。

2016-11-04 10:22:49.881 INFO 8820 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain : 创建过滤器链: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4c191377, org.springframework.security.web.context.SecurityContextPersistenceFilter@28bad32a, org.springframework.security.web.header.HeaderWriterFilter@3c3ec668,org.springframework.security.web.csrf.CsrfFilter@288460dd、org.springframework.security.web.authentication.logout.LogoutFilter@1c9cd096、org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@3990c331、org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@1e8d4ac1、org.springframework.security.web.authentication.www.BasicAuthenticationFilter@2d61d2a4、org.springframework.security.web.savedrequest.RequestCacheAwareFilter@380d9a9b、org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@abf2de3、org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2a5c161b、org.springframework.security.web.session.SessionManagementFilter@3c1fd3e5、org.springframework.security.web.access.ExceptionTranslationFilter@3d7055ef、org.springframework.security.web.access.intercept.FilterSecurityInterceptor@5d27725a]

顺便说一句,我们使用的是弹簧安全版本4.1.3.!


答案 1

从Spring Security 4.1开始,这是使Spring Security支持CORS的正确方法(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");
    }
}

和:

@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;
    }
}

不要执行以下任何操作,这是尝试解决问题的错误方法:

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

参考资料: http://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html


答案 2

由于我对其他解决方案有问题(特别是为了让它在所有浏览器中工作,例如edge不将“*”识别为“访问控制 -允许-方法”的有效值),我不得不使用自定义过滤器组件,这最终对我有用,并且完全完成了我想要实现的目标。

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods",
                "ACL, CANCELUPLOAD, CHECKIN, CHECKOUT, COPY, DELETE, GET, HEAD, LOCK, MKCALENDAR, MKCOL, MOVE, OPTIONS, POST, PROPFIND, PROPPATCH, PUT, REPORT, SEARCH, UNCHECKOUT, UNLOCK, UPDATE, VERSION-CONTROL");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, Key, Authorization");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    public void init(FilterConfig filterConfig) {
        // not needed
    }

    public void destroy() {
        //not needed
    }

}