对于单纯的 Spring cloud gateway ,解决办法是暴露一个CorsWebFilter
的Bean:
@Bean
public CorsWebFilter corsWebFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource (new PathPatternParser ());
CorsConfiguration corsConfig = new CorsConfiguration ();
// 允许所有请求方法
corsConfig.addAllowedMethod ("*");
// 允许所有域,当请求头
corsConfig.addAllowedOrigin ("*");
// 允许全部请求头
corsConfig.addAllowedHeader ("*");
// 允许携带 Cookie 等用户凭证
corsConfig.setAllowCredentials (true);
// 允许全部请求路径
source.registerCorsConfiguration ("/**", corsConfig);
return new CorsWebFilter (source);
}
这个CorsWebFilter
过滤器会被自动加入到 gateway 的过滤链中,实现对跨域options预检请求的正确响应。
另外插一嘴,spring官方给的跨域配置是在配置文件里面配置的,但是实测无效,上面介绍的配置有效。
但是对于 Spring security 以上配置就不在适用了,需要对Sping security进行单独的跨域配置,具体原因可看文末的分析。
解决办法分两种
CorsConfigurationSource
CorsConfigurationSource
的Bean,Security 自动完成注入启用 Security 的跨域配置,手动指定 CorsConfigurationSource
:
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// 异常处理配置
http.
// 其他配置
...
// 重点在这儿!
.and ()
// 1. 开始跨域配置
.cors ()
// 2. 指定一个 CorsConfigurationSource`
.configurationSource (corsConfigurationSource())
// 其他配置
.and ().csrf ().disable ();
return http.build ();
}
// 跨域配置
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource (new PathPatternParser ());
CorsConfiguration corsConfig = new CorsConfiguration ();
// 允许所有请求方法
corsConfig.addAllowedMethod ("*");
// 允许所有域,当请求头
corsConfig.addAllowedOrigin ("*");
// 允许全部请求头
corsConfig.addAllowedHeader ("*");
// 允许携带 Authorization 头
corsConfig.setAllowCredentials (true);
// 允许全部请求路径
source.registerCorsConfiguration ("/**", corsConfig);
return source;
}
上面是手动指定 CorsConfigurationSource
,其实只要暴露一个 CorsConfigurationSource
的Bean,Spring Security 会自动完成跨域配置:
@Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource (new PathPatternParser ());
CorsConfiguration corsConfig = new CorsConfiguration ();
// 允许所有请求方法
corsConfig.addAllowedMethod ("*");
// 允许所有域,当请求头
corsConfig.addAllowedOrigin ("*");
// 允许全部请求头
corsConfig.addAllowedHeader ("*");
// 允许携带 Authorization 头
corsConfig.setAllowCredentials (true);
// 允许全部请求路径
source.registerCorsConfiguration ("/**", corsConfig);
return source;
}
首先必须明确几点:
CorsWebFilter
这个过滤器来完成的。上面配置CorsConfigurationSource
,也无非是让Spring Security利用CorsConfigurationSource
自动构建出一个CorsWebFilter
添加到它的过滤链中。我们知道Spring Security也是基于过滤器的,既然是过滤器那就会涉及到一个先后的问题,事实证明 gateway 的CorsWebFilter
是在Spring Security的过滤链之后的。
一个options方法的跨域预检请求来到Spring Security的过滤链,Spring Security一看这个options请求没有携带用户凭证的Authorization头、Cookie或者token参数等信息,直接把这个请求给拦了下来,浏览器收不到正确的响应就会报跨域错误。所以如果使用了Sping security,就需要为Sping security配置跨域,让Sping security添加CorsWebFilter
到自己的过滤链中,防止跨域预检请求被直接拒了。
Spring Security 的安全过滤链中的CorsWebFilter
已经对跨域预见请求进行处理。
CorsConfigurationSource
的Bean就OK了?看源码、看源码、看源码。