Spring安全CORS过滤器

M. *_*ele 22 java spring spring-security cors spring-boot

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

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

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

我们的错误:

XMLHttpRequest无法加载http://localhost:8080/getKunden.请求的资源上不存在"Access-Control-Allow-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 {
}
}
Run Code Online (Sandbox Code Playgroud)

我们的滤镜

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

}
}
Run Code Online (Sandbox Code Playgroud)

我们的应用

@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();
}
}
Run Code Online (Sandbox Code Playgroud)

我们的过滤器是从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]

响应: 响应标头

我们从春天尝试了解决方案,但它没有用!我们控制器中的注释@CrossOrigin也没有帮助.

编辑1:

尝试了@PiotrSoł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.SecurityContextHolderAwareRe 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版本.

Hen*_*wan 65

从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");
    }
}
Run Code Online (Sandbox Code Playgroud)

和:

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

千万不能做任何的下方,这是错误的方式来尝试解决问题:

  • 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

  • 如果您不使用番石榴,则始终可以执行以下操作:Collections.unmodifiableList(Arrays.asList(“ HEAD”,...)) (3认同)
  • **不要**在不知道您在做什么的情况下删除CSRF!https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) (3认同)
  • 类型“WebMvcConfigurerAdapter”已弃用。从 Spring 5 开始,你只需要实现接口 `WebMvcConfigurer` (3认同)
  • 请注意,WebMvcConfigurerAdapter现已弃用. (2认同)
  • 仍然无法使用此解决方案,因为预检请求被阻止。 (2认同)

Dav*_*ner 17

由于我遇到其他解决方案的问题(特别是为了让它在所有浏览器中运行,例如edge不能将"*"识别为"Access-Control-Allow-Methods"的有效值),我必须使用自定义过滤组件,它最终为我工作,并完成我想要实现的目标.

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

}
Run Code Online (Sandbox Code Playgroud)


M. *_*ele 16

好的,经过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");
        }
    };
}
}
Run Code Online (Sandbox Code Playgroud)

  • 您使用的是哪种类型的身份验证?基本,形式? (3认同)

mik*_*477 9

我生命中的 8 个小时我永远不会回来......

确保在 CorsConfiguration 中设置了 Exposed Headers 和 Allowed Headers

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
    configuration.setAllowedMethods(Arrays.asList("GET","POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
    configuration.setExposedHeaders(Arrays.asList("Authorization", "content-type"));
    configuration.setAllowedHeaders(Arrays.asList("Authorization", "content-type"));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}
Run Code Online (Sandbox Code Playgroud)


小智 8

WebMvcConfigurerAdapter从 5.0 开始,该类已被弃用WebMvcConfigurer,具有默认方法,可以直接实现,无需此适配器。对于本例:

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("http://localhost:3000");
    }
}
Run Code Online (Sandbox Code Playgroud)

另请参阅:会话 cookie 的同站点标志


Pio*_*iak 7

  1. 你不需要:

    @Configuration
    @ComponentScan("com.company.praktikant")
    
    Run Code Online (Sandbox Code Playgroud)

    @EnableWebSecurity已经有了 @Configuration,我无法想象你为什么放在@ComponentScan那里.

  2. 关于CORS过滤器,我只想把它:

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0); 
        return bean;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    进入SecurityConfiguration类并删除配置和配置全局方法.您不需要两次设置allowde orgins,headers和方法.特别是如果你在过滤器和弹簧安全配置中添加不同的属性:)

  3. 根据以上所述,您的"MyFilter"类是多余的.

  4. 你也可以删除那些:

    final AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
    annotationConfigApplicationContext.register(CORSConfig.class);
    annotationConfigApplicationContext.refresh();
    
    Run Code Online (Sandbox Code Playgroud)

    来自Application类.

  5. 最后小建议 - 与问题无关.你不想把动词放在URI中.而不是http://localhost:8080/getKunden你应该在http://localhost:8080/kunden资源上使用HTTP GET方法.您可以在此处了解设计RESTful api的最佳实践:http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api


GKi*_*lin 7

使用Spring Boot 2中的Spring Security来全局配置CORS(例如,启用所有开发请求),您可以执行以下操作:

@Bean
protected CorsConfigurationSource corsConfigurationSource() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
    return source;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors()
            .and().authorizeRequests()
            .anyRequest().permitAll()
            .and().csrf().disable();
}
Run Code Online (Sandbox Code Playgroud)


The*_*ury 7

经过几个小时的研究后,这个解决方案让我解锁:

在配置中初始化 core() 选项

@Override
public void configure(HttpSecurity http) throws Exception {
http
    .cors()
    .and()
    .etc
}
Run Code Online (Sandbox Code Playgroud)

根据您的意愿在 corsFilter 中初始化您的 Credential、Origin、Header 和 Method。

@Bean
public CorsFilter corsFilter() {
  UrlBasedCorsConfigurationSource source = new 
  UrlBasedCorsConfigurationSource();
  CorsConfiguration config = new CorsConfiguration();
  config.setAllowCredentials(true);
  config.addAllowedOrigin("*");
  config.addAllowedHeader("*");
  config.addAllowedMethod("*");
  source.registerCorsConfiguration("/**", config);
  return new CorsFilter(source);
}
Run Code Online (Sandbox Code Playgroud)

我不需要使用这个类:

@Bean
public CorsConfigurationSource corsConfigurationSource() {
}
Run Code Online (Sandbox Code Playgroud)


lmi*_*lmh 5

根据CORS 过滤器文档

“Spring MVC 通过控制器上的注释为 CORS 配置提供了细粒度的支持。但是,当与 Spring Security 一起使用时,建议依赖必须在 Spring Security 的过滤器链之前订购的内置 CorsFilter

这样的事情将允许GET访问/ajaxUri

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AjaxCorsFilter extends CorsFilter {
    public AjaxCorsFilter() {
        super(configurationSource());
    }

    private static UrlBasedCorsConfigurationSource configurationSource() {
        CorsConfiguration config = new CorsConfiguration();

        // origins
        config.addAllowedOrigin("*");

        // when using ajax: withCredentials: true, we require exact origin match
        config.setAllowCredentials(true);

        // headers
        config.addAllowedHeader("x-requested-with");

        // methods
        config.addAllowedMethod(HttpMethod.OPTIONS);
        config.addAllowedMethod(HttpMethod.GET);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/startAsyncAuthorize", config);
        source.registerCorsConfiguration("/ajaxUri", config);
        return source;
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,您的 SpringSecurity 配置必须允许使用列出的方法访问 URI。请参阅@Hendy Irawan 的回答。


Gar*_*yan 5

很多地方看到需要加这段代码的答案:

@Bean
public FilterRegistrationBean corsFilter() {
   UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
   CorsConfiguration config = new CorsConfiguration();
   config.setAllowCredentials(true);
   config.addAllowedOrigin("*");
   config.addAllowedHeader("*");
   config.addAllowedMethod("*");
   source.registerCorsConfiguration("/**", config);
   FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
   bean.setOrder(0); 
   return bean;
}
Run Code Online (Sandbox Code Playgroud)

但就我而言,它引发了意外的类类型异常。corsFilter()bean 需要CorsFilter类型,所以我已经完成了这些更改并将 bean 的这个定义放在我的配置中,现在一切正常。

@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}
Run Code Online (Sandbox Code Playgroud)