前提
在项目使用了 WebMvcConfigurer类的addCorsMappings方法配置跨域,addInterceptors方法添加权限校验拦截
问题
平时表现正常,但是一旦interceptor拦截了没权限的请求时会发现该请求跨域也失效了
查找
先看Cors是在哪里起的作用,追踪代码
首先是请求进到DispatcherServlet的doDispatch方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
mappedHandler = getHandler(processedRequest);
...
}
再通过遍历去获取真正对应的HandlerMapping
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
如果发现是个跨域请求,做特殊处理
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
...
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
这里看到所谓的特殊处理,其实就是再加上一个interceptor
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
if (CorsUtils.isPreFlightRequest(request)) {
HandlerInterceptor[] interceptors = chain.getInterceptors();
chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
}
else {
chain.addInterceptor(new CorsInterceptor(config));
}
return chain;
}
看到这里就能发现问题所在了,因为按照上面的配置其实是把处理跨域放在了最后一个interceptor上,而interceptor就是按照顺序处理的,所以一旦前面的interceptor拦截了请求,最后一个cors的interceptor就会被断路掉。
解决
有两个方法可以解决
- 提高
corsInterceptor的优先级,所以就不能借助于spring的addCorsMappings方法了,只能手动配置一个crosInterceptor,且优先于其它的interceptor - 在
interceptor前面就把请求处理了:添加一个corsFilter。关于filter和interceptor的区别可以查资料,这里只需要知道filter总在interceptor之前处理就ok了
PS
spring社区在2019.4月已经有人提交了关于这个先后顺序的fix, chain.addInterceptor(new CorsInterceptor(config)); 改成了
chain.addInterceptor(0,new CorsInterceptor(config)); 不过后续发布的5.1.XRELEASE 都没加上。直到5.2.X才合并了这个修改。