弹簧安全CORS过滤器

新手上路,请多包涵

我们在现有项目中添加了 Spring Security

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

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

我们的错误:

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

我们的安全配置:

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

我们的过滤器是从 spring-boot 注册的:

2016-11-04 09:19:51.494 INFO 9704 — [ost-startStop-1] osbwservlet.FilterRegistrationBean:映射过滤器:“myFilter”到:[/*]

我们生成的过滤器链:

2016-11-04 09:19:52.729 INFO 9704 — [ost-startStop-1] ossweb.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.ExceptionTra nslationFilter@4b8bf1fb, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@42063cf1]

响应: 响应标头

我们也尝试了 spring 的解决方案,但没有奏效!我们控制器中的注释 @CrossOrigin 也没有帮助。

编辑1:

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

2016-11-04 10:22:49.881 INFO 8820 — [ost-startStop-1] ossweb.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.SecurityContextHolderAwareReRe questFilter@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]

顺便说一句,我们使用的是 spring-security 版本 4.1.3。!

原文由 Mace 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 474
2 个回答

好的,经过2天多的搜索,我们终于解决了这个问题。我们删除了所有过滤器和配置,而是在应用程序类中使用了这 5 行代码。

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

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedOrigins("http://localhost:3000");
            }
        };
    }
}

原文由 Mace 发布,翻译遵循 CC BY-SA 4.0 许可协议

从 Spring Security 4.1 开始,这是使 Spring Security 支持 CORS 的正确方法(在 Spring Boot 1.41.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

原文由 Hendy Irawan 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题