Webflux 跨域设置及与权限冲突的解决办法
网上提供了2种跨域的设置方式
1为 重写 WebFluxConfigurer 的 addCorsMappings。
2为 提供一个 WebFilter 或 CorsWebFilter。
注意点,如果有权限验证的filter,建议使用第二种凡是,且CorsWebFilter一定要优先于AuthFilter过滤,否则跨域的PreFilght将一直失败,无法实现跨域。
Cors原理如下:
浏览器将cors请求分为两类即简单请求和非简单请求.
简单请求
只要同时满足以下条件就属于简单请求
请求方法是以下三种方法之一:GET POST HEAD
Http的头信息不超出以下几种字段:Accept Accept-Language Content-Language Last-Event-ID Content-Type 只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
非简单请求
其他的请求皆属于非简单请求.
注意在cors定义中,如果头信息中的Content-Type不设置,则默认值为json/application,如果Content-Type值不为application/x-www-form-urlencoded,multipart/form-data或text/plain,都被视为非简单请求,即预检请求.
简单请求
只要同时满足以下条件就属于简单请求
请求方法是以下三种方法之一:GET POST HEAD
Http的头信息不超出以下几种字段:Accept Accept-Language Content-Language Last-Event-ID Content-Type 只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
非简单请求
其他的请求皆属于非简单请求.
注意在cors定义中,如果头信息中的Content-Type不设置,则默认值为json/application,如果Content-Type值不为application/x-www-form-urlencoded,multipart/form-data或text/plain,都被视为非简单请求,即预检请求.
浏览器对这两种请求的处理是不一样的.
如果是简单请求的话,一次完整的请求过程是不需要服务端预检的,直接响应回客户端。
而非简单请求则浏览器会在发送真正请求之前先用OPTIONS发送一次预检请求preflight request,从而获知服务端是否允许该跨域请求,当服务器确认允许之后,才会发起真正的请求.
那么带有权限的非简单请求,首先要触发了一次预检请求,但由于服务端使用了权限认证框架,通过拦截用户请求头中传过来的token信息来判定客户端是否为非法调用,而Preflight请求过程中并不会携带我们自定义的token信息到服务器,这样服务器校验就永远也无法通过了,就算是合法的登录用户也会被拦截.
附:CorsWebFilter代码
/** * 跨域Filter */ @Configuration @Data public class CorsFilter implements WebFluxConfigurer { @Value("#{'${cors.allowedOrigins:*}'.split(',')}") private List<String> allowedOrigins; @Value("#{'${cors.allowedHeaders:*}'.split(',')}") private List<String> allowedHeaders; @Value("#{'${cors.allowedMethods:*}'.split(',')}") private List<String> allowedMethods; @Value("${cors.corsMapping:/**}") private String corsMapping; /** * corsWebFilter需要早于AuthFiler */ @Bean @Order(-200) //非常重要,一定要早于AuthFilter CorsWebFilter corsWebFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); for(String val:allowedOrigins){ config.addAllowedOrigin(val); } for(String val:allowedHeaders){ config.addAllowedHeader(val); } for(String val:allowedMethods){ config.addAllowedMethod(val); } UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(corsMapping, config); return new CorsWebFilter(source); } }