Springboot corsMapping和interceptor的小冲突

2,250 阅读2分钟
前提

在项目使用了 WebMvcConfigurer类的addCorsMappings方法配置跨域,addInterceptors方法添加权限校验拦截

问题

平时表现正常,但是一旦interceptor拦截了没权限的请求时会发现该请求跨域也失效了

查找

先看Cors是在哪里起的作用,追踪代码

首先是请求进到DispatcherServletdoDispatch方法

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就会被断路掉。

解决

有两个方法可以解决

  1. 提高corsInterceptor的优先级,所以就不能借助于spring的addCorsMappings方法了,只能手动配置一个crosInterceptor,且优先于其它的interceptor
  2. 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才合并了这个修改。