Zuul Proxy CORS 头包含多个值,头重复两次 - Java Spring Boot CORS 过滤器配置

Posted

技术标签:

【中文标题】Zuul Proxy CORS 头包含多个值,头重复两次 - Java Spring Boot CORS 过滤器配置【英文标题】:Zuul Proxy CORS header contains multiple values, headers repeated twice - Java Spring Boot CORS filter config 【发布时间】:2016-07-02 18:10:04 【问题描述】:

为什么我会让每个 CORS 标头都加倍?我正在使用 Zuul 代理通过 API 网关对服务的请求进行代理。

我的 spring 安全过滤顺序一定有错误配置。

当我访问需要身份验证的路由时,我收到如下错误:

通过 API Gateway 请求服务错误

XMLHttpRequest cannot load https://myservice.mydomain.com:8095/service/v1/account/txHistory?acctId=0.  
The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. 
Origin 'http://localhost:9000' is therefore not allowed access.

Chrome 网络日志

我检查了 Chrome devtools 中的响应,果然 CORS 标头重复了两次:

所以这看起来好像每次回复都会调用我的 CORS 过滤器两次。我不知道为什么会在这一点上发生。可能是我的过滤器是在 ChannelProcessingFilter 之前添加的。

API Gateway CORS 过滤器代码:

public class SimpleCORSFilter implements Filter 

    @Override
    public void init(FilterConfig filterConfig) throws ServletException 

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
        HttpServletResponse res = (HttpServletResponse) response;
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
        res.setHeader("Access-Control-Max-Age", "3600");
        res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, x-requested-with, Cache-Control");
        chain.doFilter(request, res);
    

    @Override
    public void destroy() 

我的 API Gateway 安全配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception 
        return super.authenticationManagerBean();
    

    @Inject
    public void setUserDetailsService(UserDetailsService userDetailsService) 
        this.userDetailsService = userDetailsService;
    

    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception 
        authenticationManagerBuilder.userDetailsService(userDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
    

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception 
        httpSecurity
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
           .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers("/health","/metrics", "/v1/users/register").permitAll()
                .antMatchers("/mappings", "/v1/**", "/service/**").authenticated()
                .and()
            .httpBasic()
                .realmName("apiRealm")
                .and()
            .csrf()
                .disable()
            .headers()
                .frameOptions().disable()
            .and().addFilterBefore(new SimpleCORSFilter(), ChannelProcessingFilter.class);
    


我可以通过检查标头是否为 null 来解决这个问题,然后仅在它为空或 null 时才设置它,尽管这似乎不是最好的解决方案。我想了解我做了什么导致标题被预设两次。

【问题讨论】:

【参考方案1】:

对我来说,这个解决方案可以解决 zuul 中的 CORS 问题。

endpoints.cors.allowed-origins=*
endpoints.cors.allowed-headers=*
endpoints.cors.allowed-methods=*

但是,这在我的一个暂存环境中似乎对我不起作用。

【讨论】:

【参考方案2】:

我也遇到了同样的问题,我在有@EnableZuulProxy的类中添加了CorsFilter,但还是没有解决我的问题。

根据github Q&A Zuul Access-Control-* Headers are duplicated

zuul.ignored-headers=Access-Control-Allow-Credentials, Access-Control-Allow-Origin

将其添加到我的 zuul 的 bootstrap.properties 中,它可以工作!!!

【讨论】:

绝对省钱!!!【参考方案3】:

我遇到了类似的问题,但问题是我在 APIGateway 和其他服务中都有 CORS 过滤器。如果这不是你的情况,那么试试这个 CORS 过滤器。

将此添加到您在 API 网关中拥有 @EnableZuulProxy 的类。这应该可以解决我的问题。

@Bean
public CorsFilter corsFilter() 
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("HEAD");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("DELETE");
    config.addAllowedMethod("PATCH");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);

【讨论】:

我最终在我的 API 网关和我的一项服务中使用了 CORS。我通过仅在我的 API 网关中使用 CORS 来解决它。感谢您发布 CorsFilter bean 定义! 如果您不能/不想更改其他服务的安全配置怎么办?我尝试检查过滤器中的标头,但即使有服务设置的标头,它也总是返回 null @Jamby 您可能会使用 UrlBasedCorsConfigurationSource 对象来查看...。此配置适用于所有人,因为它说注册到所有 URL 的 source.registerCorsConfiguration("/**", config) ; 你可以有你想要这些配置的特定网址。 @GrinishNepal 这将需要对云中可用的其他服务的编码了解依赖性,其中隐藏此信息是 API 网关的主要目的。我只是想要一个过滤器,如果服务端尚未支持(并且不会破坏它),它会动态添加 CORS 支持。 如果您创建一个问题会更好,以便您可以获得所需的确切帮助。

以上是关于Zuul Proxy CORS 头包含多个值,头重复两次 - Java Spring Boot CORS 过滤器配置的主要内容,如果未能解决你的问题,请参考以下文章

servlet 相应头重定向

CORS 政策问题刚刚开始,没有代码更改 - “CORS 政策:'Access-Control-Allow-Origin' 标头包含多个值”

CORS问题:标头包含多个值,但只允许一个

Angular4 CORS 标头包含多个值

被 CORS 策略阻止:“Access-Control-Allow-Origin”标头包含多个值“*、*”,但只允许一个

zuul+security跨域Cors问题解决