Tomcat 8 和 Spring Security Cors

Posted

技术标签:

【中文标题】Tomcat 8 和 Spring Security Cors【英文标题】:Tomcat 8 and Spring Security Cors 【发布时间】:2020-02-26 17:18:16 【问题描述】:

我正在尝试配置 Spring Security 以使其支持 CORS。 感谢这篇文章 Spring security CORS Filter,我已经使用 Spring Boot 使用此配置代码在我的本地主机上工作了:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter 
    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.cors()
        .and()
        .antMatcher("/api/**")
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .authorizeRequests()
        .antMatchers(HttpMethod.POST, "/api/login").permitAll()
        .antMatchers(HttpMethod.GET, "/api/websocket/**").permitAll()
        .antMatchers("/api/**").authenticated()
        .and()
        .addFilterBefore(new JWTLoginFilter("/api/login", HttpMethod.POST, authenticationManager(), tokenAuthenticationService, myUserService), UsernamePasswordAuthenticationFilter.class)
        .addFilterBefore(new JWTAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class)
        .csrf().disable();
    

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

但是当我在远程 Tomcat 服务器上部署我的应用程序时,它不起作用:

 Access to XMLHttpRequest at 'http://xxx:9080/yyy/api/user/findByLogin/?login=zzz' from origin 'http://xxx:10080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这是失败的 OPTIONS 请求的屏幕截图:

我的本​​地主机上的工作请求:

我的配置类是否足够,或者我需要在 Tomcat 设置中进行设置吗? 谢谢

【问题讨论】:

你能检查你的 OPTIONS 请求是否给出了 CORS 错误吗?如果是这样,请将其添加到您允许的方法中,然后重试。 OPTIONS 请求返回 403。我添加了屏幕截图。 你能看看这篇文章吗? ***.com/questions/43699343/… 同理,解决方案在本地有效,在Tomcat上无效。 你的 pom.xml 和 main 类是什么样子的?请尝试提供minimal reproducible example。 【参考方案1】:

响应 403 反映了授权失败。可能是您的服务器设置为请求选项请求的授权。您必须确保将选项配置为发送成功响应(2xx 状态代码)以允许浏览器发送实际请求。 2xx 响应通知浏览器服务器处理 CORS 请求。

您的请求在本地有效的原因可能是您在提出请求时获得了授权。因此,请检查您的身份验证以确保其正确。因此,飞行前请求不会发送任何授权标头,因此您不应期望在服务器端。

【讨论】:

【参考方案2】:

只需配置 CorsFilter 以使用提供的 CorsConfigurationSource 添加相关的 CORS 响应标头(如 Access-Control-Allow-Origin)。阅读其文档了解更多信息。由于您已经拥有UrlBasedCorsConfigurationSource,您可以将过滤器配置如下:

@Bean
  public FilterRegistrationBean corsFilter() 
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(corsConfigurationSource()));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
  

只要在你的配置中加入上面提到的 bean,希望它可以工作。

这是我的完整配置,您只需要上面提到的一部分:

@Bean
  public FilterRegistrationBean corsFilter() 
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    config.addExposedHeader("Content-Disposition");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
  

【讨论】:

【参考方案3】:
    您的允许方法也应该有“OPTIONS”。 您是否拥有 Web 服务器?网络服务器是否也有 CORS?

【讨论】:

【参考方案4】:

    尝试在本地的corsConfigurationSource() 方法中放置一个调试点并检查它是否正在执行。如果它没有被执行,请调查原因 - 可能通过启用 Spring 的调试日志和/或重新检查 Spring 配置。

    另外,尝试将 OPTIONS 添加到 setAllowedMethods

    configuration.setAllowedMethods(ImmutableList.of("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
    

【讨论】:

【参考方案5】:

检查 tomcat 服务器是否在 $CATALINA_BASE/conf/web.xml 中配置了冲突的 CORS 过滤器

【讨论】:

【参考方案6】:

Tomcat 也有自己的 cors 过滤器,如果您在 tomcat 之前使用其他服务器(如 nodejs、apache 服务器 vs )也要检查它的 cors 过滤器。

【讨论】:

【参考方案7】:

Spring security 提供了一种在 http 配置器中配置 CORS 的方法,有一种更简洁的方法可以将 CORS 过滤器添加到应用程序中-

@Component 
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCORSFilterClass implements Filter 
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
throws IOException, ServletException 
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;

response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);

@Override
public void init(FilterConfig filterConfig) 


@Override
public void destroy() 


以最高优先级排序过滤器确保 javax.servlet.Filter 的 MyCORSFilterClassimplementation 是链中的第一个。

【讨论】:

使用过滤器,它可以在本地工作(如果你在 WebSecurityConfigurerAdapter 中添加 http.cors()),但仍然不能在我的 Tomcat 服务器上。 对我来说同样的问题。任何解决方案@ClémentPicou?

以上是关于Tomcat 8 和 Spring Security Cors的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat 8 和 Spring Security Cors

Spring Boot YML 和独立 Tomcat 8 服务器

Spring Security 和 Tomcat 8 JSessionId 响应不匹配

Spring Security和Tomcat 8 JSessionId响应不匹配

Grails 3 Spring Security LDAP 插件和 Tomcat 8

在调用处理程序之前使用 Tomcat 8 和 Spring 4 ClassCastException 的 websockets