如何为不同的URL堆叠CORS过滤器?

时间:2018-11-27 10:58:24

标签: java spring spring-security cors

我有一个Spring Boot 2 REST API作为我的React应用程序的后端。该网站和API托管在不同的子域(分别为https://example.comhttps://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;
}

但是,这不起作用,并且当未知来源尝试访问403 Invalid CORS request端点时会返回/saml/**


我想这里的问题是,即使存在与请求匹配的更具体的蚂蚁模式/**,更通用的/saml/**模式仍然优先。

我不想显式配置所有其他端点以允许网站起源,但希望它成为与任何其他CORS配置都不匹配的请求的全部。


如何允许任何来源访问/saml/**,同时仍然只允许https://example.com访问所有其他地点/**

2 个答案:

答案 0 :(得分:2)

您可以扩展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;
}

答案 1 :(得分:0)

通过将CorsConfiguration添加到LinkedHashMap内部的UrlBasedCorsConfigurationSource中来注册它们。这意味着顺序会保留下来,只需要按照正确的顺序添加CorsConfiguration即可:

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