跨域资源共享(CORS)是一种机制,用于控制对当前源之外的资源的AJAX调用。在某些情况下,您需要允许某些来源进行此类呼叫。例如,如果您有一个基于SAAS的产品,那么会有一些客户端连接到您的API并进行AJAX调用。
在Spring中,有几种方法可以检查传入请求的来源,方法,标头等。
您可以使用WebSecurityConfigurerAdapterSpring Security的,并且WebMvcConfigurer,@CrossOrigin注释,CorsFilterSpring MVC中。
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课,然后看课里面有什么。它简单地扩展OncePerRequestFilter,CorsConfigurationSource在其构造函数中设置对象,并doFilterInternal借助进行方法中的所有过滤DefaultCorsProcessor。
CorsFilter
OncePerRequestFilter
CorsConfigurationSource
doFilterInternal
DefaultCorsProcessor
我决定写我们CorsFilter延伸OncePerRequestFilter,利用DefaultCorsProcessor处理CORS请求,做一样的事情CorsFilter确实在doFilterInternal方法,并在运行时创建CorsConfiguration。另外,我需要创建一个新服务并将其添加为依赖项,以从数据源动态获取来源。我创建了OriginService类,该类从我们的数据源获取客户端的起源。我们的自定义cors过滤器的主要区别是在运行时通过OriginService获取源来创建CorsConfiguration。
CorsConfiguration
OriginService
我们的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