如何为不同的 URL 堆叠 CORS 过滤器?
Posted
技术标签:
【中文标题】如何为不同的 URL 堆叠 CORS 过滤器?【英文标题】:How do I stack CORS filters for different URLs? 【发布时间】:2019-04-29 02:29:28 【问题描述】:我有一个 Spring Boot 2 REST API 作为我的 React 应用程序的后端。网站和 API 托管在不同的子域上(分别为 https://example.com
和 https://api.example.com
),所以我设置了一个 CORS 过滤器来支持这一点:
@Bean
public FilterRegistrationBean corsFilter()
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration apiCorsConfig = new CorsConfiguration();
apiCorsConfig.addAllowedOrigin("https://example.com");
apiCorsConfig.addAllowedHeader(CorsConfiguration.ALL);
apiCorsConfig.addAllowedMethod(CorsConfiguration.ALL);
apiCorsConfig.setMaxAge(600L);
source.registerCorsConfiguration("/**", apiCorsConfig);
FilterRegistrationBean filterRegistrationBean =
new FilterRegistrationBean<>(new CorsFilter(source));
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
这很好用。
我现在已经实现了 Spring SAML 来支持 SAML 作为对 API 进行身份验证的替代方法。所有 SAML 端点都放在/saml/**
下。 SAML 身份验证请求可以来自任何来源,因此我需要打开这些端点以允许来自任何来源的 CORS 请求。
我尝试了以下方法:
@Bean
public FilterRegistrationBean corsFilter()
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration apiCorsConfig = new CorsConfiguration();
apiCorsConfig.addAllowedOrigin("https://example.com");
apiCorsConfig.addAllowedHeader(CorsConfiguration.ALL);
apiCorsConfig.addAllowedMethod(CorsConfiguration.ALL);
apiCorsConfig.setMaxAge(600L);
source.registerCorsConfiguration("/**", apiCorsConfig);
CorsConfiguration samlCorsConfig = new CorsConfiguration();
samlCorsConfig.addAllowedOrigin(CorsConfiguration.ALL);
samlCorsConfig.addAllowedHeader(CorsConfiguration.ALL);
samlCorsConfig.addAllowedMethod(CorsConfiguration.ALL);
samlCorsConfig.setMaxAge(600L);
source.registerCorsConfiguration("/saml/**", samlCorsConfig);
FilterRegistrationBean filterRegistrationBean =
new FilterRegistrationBean<>(new CorsFilter(source));
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
但是,这不起作用,当未知来源尝试访问 /saml/**
端点时,会返回 403 Invalid CORS request
。
我想这里的问题是更通用的 /**
模式优先,即使有更具体的 ant-pattern /saml/**
匹配请求。
我不想明确配置所有其他端点以允许网站来源,但希望它成为与任何其他 CORS 配置不匹配的请求的包罗万象。
我怎样才能允许任何来源访问/saml/**
,同时仍然只允许https://example.com
访问所有其他端点/**
?
【问题讨论】:
我认为你可以用@CrossOrigin('*') 注释你的控制器类,它使用了@RequestMapping('/saml') 没有明确的 SAML 控制器,因为这些端点由 Spring SAML 处理。 该答案解决了多个预定义的允许来源保护单个路径模式,这与我的问题不同。 CORS with spring-boot and angularjs not working的可能重复 【参考方案1】:您可以扩展UrlBasedCorsConfigurationSource
并覆盖getCorsConfiguration
:
public class CustomeUrlBasedCorsConfigurationSource extend UrlBasedCorsConfigurationSource
@Override
@Nullable
public CorsConfiguration getCorsConfiguration(HttpServletRequest request)
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
if(this.pathMatcher.match("/saml/**",lookupPath))
return this.corsConfigurations.get("/saml/**");
return super.getCorsConfiguration(request);
您的配置应该类似于:
@Bean
public FilterRegistrationBean corsFilter()
CustomeUrlBasedCorsConfigurationSource source = new CustomeUrlBasedCorsConfigurationSource();
CorsConfiguration apiCorsConfig = new CorsConfiguration();
apiCorsConfig.addAllowedOrigin("https://example.com");
apiCorsConfig.addAllowedHeader(CorsConfiguration.ALL);
apiCorsConfig.addAllowedMethod(CorsConfiguration.ALL);
apiCorsConfig.setMaxAge(600L);
source.registerCorsConfiguration("/**", apiCorsConfig);
CorsConfiguration samlCorsConfig = new CorsConfiguration();
samlCorsConfig.addAllowedOrigin(CorsConfiguration.ALL);
samlCorsConfig.addAllowedHeader(CorsConfiguration.ALL);
samlCorsConfig.addAllowedMethod(CorsConfiguration.ALL);
samlCorsConfig.setMaxAge(600L);
source.registerCorsConfiguration("/saml/**", samlCorsConfig);
FilterRegistrationBean filterRegistrationBean =
new FilterRegistrationBean<>(new CorsFilter(source));
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
【讨论】:
感谢您的回答,这应该可以解决问题。但是,我不喜欢将端点配置复制到单独的类中。一个想法是有一个UrlBasedCorsConfigurationSource
实现,它按照添加的顺序遍历不同的CorsConfiguration
s(而不是像UrlBasedCorsConfigurationSource
那样以未定义的顺序循环遍历条目集)。然后,您可以先添加更具体的CorsConfiguration
s,如果没有找到是否会回退到最一般的/**
。
好吧,我会被诅咒的。情况已经如此,因为CorsConfiguration
s 被添加到保持其顺序的LinkedHashMap
。然后只需按正确的顺序添加CorsConfigurations
。感谢您帮我找到这个!【参考方案2】:
CorsConfiguration
s 是通过将它们添加到 UrlBasedCorsConfigurationSource
内的 LinkedHashMap
来注册的。这意味着订单被保留,只需按正确的顺序添加CorsConfiguration
s:
@Bean
public FilterRegistrationBean corsFilter()
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration samlCorsConfig = new CorsConfiguration();
samlCorsConfig.addAllowedOrigin(CorsConfiguration.ALL);
samlCorsConfig.addAllowedHeader(CorsConfiguration.ALL);
samlCorsConfig.addAllowedMethod(CorsConfiguration.ALL);
samlCorsConfig.setMaxAge(600L);
source.registerCorsConfiguration("/saml/**", samlCorsConfig);
CorsConfiguration apiCorsConfig = new CorsConfiguration();
apiCorsConfig.addAllowedOrigin("https://example.com");
apiCorsConfig.addAllowedHeader(CorsConfiguration.ALL);
apiCorsConfig.addAllowedMethod(CorsConfiguration.ALL);
apiCorsConfig.setMaxAge(600L);
source.registerCorsConfiguration("/**", apiCorsConfig);
FilterRegistrationBean filterRegistrationBean =
new FilterRegistrationBean<>(new CorsFilter(source));
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
【讨论】:
以上是关于如何为不同的 URL 堆叠 CORS 过滤器?的主要内容,如果未能解决你的问题,请参考以下文章
用于 localhost 和暂存 url 的 Cors 过滤器