今天遇到一个问题,就是spring中配置cors没有效果。原来是由于被spring security拦截处理了。配置了CorsFilter在Spring security过滤器链以后,而经过WebMvcConfigurationSupport配置的CorsConfiguration则是Spring MVC中的, 更是在Spring security过滤器链的后面, 所以没有效果。而经过配置CorsConfigurationSource则会在Spring Security的过滤链中加上CORS过滤器。html
Spring security的文档这样说:
Spring中添加CORS配置最简单的方法是经过CorsFilter, 也能够经过配置CorsConfigurationSource来使spring security使用cors, 这样会把CorsFilter加到Spring security的过滤器链中。web
个人发现:
在Spring webFlux security中, 若是本身定义CorsFitler, 必须保证在Spring security的过滤器链以前, 这样才不会被Spring Security拦截处理, 从而没有了Cors过滤器。经过指定过滤器的Order为 @Order(Ordered.HIGHEST_PRECEDENCE)会在Spring security的过滤器链以前处理。spring
而在Spring Web Security 中则能够直接指定CorsFilter, Spring security会直接使用已有的CorsFilter。
https://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.htmlmvc
看下Spring webflux security是如何把cors加到过滤器链中的:
在http.build()中app
if (this.cors != null) { this.cors.configure(this); }
protected void configure(ServerHttpSecurity http) { CorsWebFilter corsFilter = this.getCorsFilter(); if (corsFilter != null) { http.addFilterAt(this.corsFilter, SecurityWebFiltersOrder.CORS); } }
private CorsWebFilter getCorsFilter() { if (this.corsFilter != null) { return this.corsFilter; } else { CorsConfigurationSource source = (CorsConfigurationSource)ServerHttpSecurity.this.getBeanOrNull(CorsConfigurationSource.class); if (source == null) { return null; } else { CorsProcessor processor = (CorsProcessor)ServerHttpSecurity.this.getBeanOrNull(CorsProcessor.class); if (processor == null) { processor = new DefaultCorsProcessor(); } this.corsFilter = new CorsWebFilter(source, (CorsProcessor)processor); return this.corsFilter; } } }
而经过ServerHttpSecurity.this.getBeanOrNull()
方法获取容器中的bean, 从而在这里获取CorsConfigurationSource实例配置CORS。cors
而在spring web security中彷佛spring security是能够识别CorsFilter并使用的, 这里没有实际测试过。async
@Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .cors().disable() .httpBasic().disable() .formLogin().disable() .addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class) .authorizeRequests() .antMatchers("/actuator/**").permitAll() .antMatchers( "/company/user/check/**", ).permitAll() .anyRequest().authenticated() .and() .exceptionHandling().authenticationEntryPoint(defaultAuthenticationEntryPoint); }
而在HttpSecurity类中ide
public CorsConfigurer<HttpSecurity> cors() throws Exception { return (CorsConfigurer)this.getOrApply(new CorsConfigurer()); }
Spring web security CorsConfigurer中:测试
private CorsFilter getCorsFilter(ApplicationContext context) { if (this.configurationSource != null) { return new CorsFilter(this.configurationSource); } else { boolean containsCorsFilter = context.containsBeanDefinition("corsFilter"); if (containsCorsFilter) { return (CorsFilter)context.getBean("corsFilter", CorsFilter.class); } else { boolean containsCorsSource = context.containsBean("corsConfigurationSource"); if (containsCorsSource) { CorsConfigurationSource configurationSource = (CorsConfigurationSource)context.getBean("corsConfigurationSource", CorsConfigurationSource.class); return new CorsFilter(configurationSource); } else { boolean mvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.handler.HandlerMappingIntrospector", context.getClassLoader()); return mvcPresent ? CorsConfigurer.MvcCorsFilter.getMvcCorsFilter(context) : null; } } } }
首先检查CorsFilter, 而后检查CorsConfigurationSource bean。
此时直接设置CorsFilter是能够加到spring security过滤器链中的。ui
Spring MVC的文档这样说:
Spring MVC 的HandlerMapping实现内置支持CORS, 在成功映射一个请求到一个handler以后, HandlerMapping会检查CORS配置以采起下一步动做。
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors-processing
个人发现:
Spring MVC会在找到handler后经过添加一个拦截器来检查CORS配置。
Spring MVC的CORS是在找到hander以后, 这个更是在Spring security的过滤器链以后, 从而cors没有效果。
下面来看一下Spring MVC中的CORS的实现。
DispatcherServlet调用AbstractHandlerMapping中的getHandler()方法:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = this.getHandlerInternal(request); if (handler == null) { handler = this.getDefaultHandler(); } if (handler == null) { return null; } else { if (handler instanceof String) { String handlerName = (String)handler; handler = this.obtainApplicationContext().getBean(handlerName); } HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request); if (this.logger.isTraceEnabled()) { this.logger.trace("Mapped to " + handler); } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) { this.logger.debug("Mapped to " + executionChain.getHandler()); } if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request); CorsConfiguration config = globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig; executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; } }
自动加上一个cors的拦截器:
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request, HandlerExecutionChain chain, @Nullable CorsConfiguration config) { if (CorsUtils.isPreFlightRequest(request)) { HandlerInterceptor[] interceptors = chain.getInterceptors(); chain = new HandlerExecutionChain(new AbstractHandlerMapping.PreFlightHandler(config), interceptors); } else { chain.addInterceptor(new AbstractHandlerMapping.CorsInterceptor(config)); } return chain; }
private class CorsInterceptor extends HandlerInterceptorAdapter implements CorsConfigurationSource { @Nullable private final CorsConfiguration config; public CorsInterceptor(@Nullable CorsConfiguration config) { this.config = config; } public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return AbstractHandlerMapping.this.corsProcessor.processRequest(this.config, request, response); } @Nullable public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { return this.config; } }
DefaultCorsProcessor
public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request, HttpServletResponse response) throws IOException { if (!CorsUtils.isCorsRequest(request)) { return true; } else { ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response); if (this.responseHasCors(serverResponse)) { logger.trace("Skip: response already contains \"Access-Control-Allow-Origin\""); return true; } else { ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request); if (WebUtils.isSameOrigin(serverRequest)) { logger.trace("Skip: request is from same origin"); return true; } else { boolean preFlightRequest = CorsUtils.isPreFlightRequest(request); if (config == null) { if (preFlightRequest) { this.rejectRequest(serverResponse); return false; } else { return true; } } else { return this.handleInternal(serverRequest, serverResponse, config, preFlightRequest); } } } } }
dispatcherServlet中在真正invoke handler以前调用拦截器:
doDispatch方法:
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; }
从而经过加的cors拦截器阻止请求。