在运行时自定义CORS过滤


跨域资源共享(CORS)是一种机制,用于控制对当前源之外的资源的AJAX调用。在某些情况下,您需要允许某些来源进行此类呼叫。例如,如果您有一个基于SAAS的产品,那么会有一些客户端连接到您的API并进行AJAX调用。

在Spring中,有几种方法可以检查传入请求的来源,方法,标头等。

您可以使用WebSecurityConfigurerAdapterSpring Security的,并且WebMvcConfigurer@CrossOrigin注释,CorsFilterSpring MVC中。

我们正在提供基于SaaS的付款和钱包应用程序。我们正在通过JavaScript提供付款页面,因此有许多CORS请求来自我们的客户。在我们的案例中,我们需要动态更改允许的来源,因为可能会添加,删除或更新某些商家。

我们在此项目中的技术堆栈包括Spring Boot,Spring Cloud,Netflix OSS,而我们的网关是Netflix Zuul。

我以为在网关中过滤CORS请求是最佳选择,我开始查看Spring提供给我们的解决方案,然后选择在我们的一个Configuration类中创建一个CorsFilter bean。我们的配置如下。

@Bean
public CorsFilter corsFilter() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.setAllowedOrigins(clientService.getClientOrigins());
    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);

经过一些测试之后,我注意到,正如您所猜测的那样,在创建bean之后就无法更新允许的来源。因为CorsFilter的configSource属性是在创建bean时设置的,所以以后不能更改。

我复习了CorsFilter课,然后看课里面有什么。它简单地扩展OncePerRequestFilterCorsConfigurationSource在其构造函数中设置对象,并doFilterInternal借助进行方法中的所有过滤DefaultCorsProcessor

我决定写我们CorsFilter延伸OncePerRequestFilter,利用DefaultCorsProcessor处理CORS请求,做一样的事情CorsFilter确实在doFilterInternal方法,并在运行时创建CorsConfiguration。另外,我需要创建一个新服务并将其添加为依赖项,以从数据源动态获取来源。我创建了OriginService类,该类从我们的数据源获取客户端的起源。我们的自定义cors过滤器的主要区别是在运行时通过OriginService获取源来创建CorsConfiguration

我们的CustomCorsFilter类如下。

@Component
public class CustomCorsFilter extends OncePerRequestFilter {

    @Autowired
    OriginService originService;

    private final CorsProcessor processor = new DefaultCorsProcessor();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        List<String> origins = originService.getOrigins();
        config.setAllowedOrigins(origins);
        config.setAllowedMethods(List.of("OPTIONS", "HEAD", "GET", "POST"));
        config.addAllowedHeader("*");
        source.registerCorsConfiguration("/**", config);
        CorsConfiguration corsConfiguration = source.getCorsConfiguration(request);
        boolean isValid = this.processor.processRequest(corsConfiguration, request, response);
        if (!isValid || CorsUtils.isPreFlightRequest(request)) {
            return;
        }
        filterChain.doFilter(request, response);
    }
}

我们的CorsFilter确实在做我们想要的。更改客户的来源后,CorsConfiguration也将更改,并且开始对新的来源列表进行Cors过滤。

这是我们针对问题的解决方案,这种情况下可能会有一些不同且更简单的解决方案。但是我们的解决方案运行良好。可以更改类以实现非常灵活的配置。这取决于您的需求。


原文链接:http://codingdict.com