SpringBoot跨域加SpringSecurity就失效( 五 )
CORS 验证失败时调用这个方法 , 并设置状态码为 403 。
5.2.3 小结通过对源码的研究 , 我们发现实现 WebMvcConfigurer.addCorsMappings 方法的方式配置 CORS , 会在 Interceptor 或者 Handler 层进行 CORS 验证 。
5.3 HtttpSecurity.cors 方法做了什么在研究这个方法的行为之前 , 我们先来回想一下 , 我们调用这个方法解决的是什么问题 。
前面我们通过某种方式配置好 CORS 后 , 引入 Spring Security , CORS 就失效了 , 直到调用这个方法后 , CORS 规则才重新生效 。
下面这些原因 , 导致了 preflight request 无法通过身份验证 , 从而导致 CORS 失效:
- preflight request 不会携带认证信息 。
- Spring Security 通过 Filter 来进行身份验证 。
- Interceptor 和 HttpRequestHanlder 在 DispatcherServlet 之后被调用 。
- Spring Security 中的 Filter 优先级比我们注入的 CorsFilter 优先级高 。
5.3.1 CorsConfigurer 如何配置 CORS 规则HttpSecurity.cors 方法中其实只有一行代码:
public CorsConfigurer cors() throws Exception {return getOrApply(new CorsConfigurer<>());}这里调用的 getOrApply 方法会将 SecurityConfigurerAdapter 的子类实例加入到它的父类 AbstractConfiguredSecurityBuilder 维护的一个 Map 中 , 然后一个个的调用 configure 方法 。 所以 , 我们来关注一下 CorsConfigurer.configure 方法就好了 。@Overridepublic void configure(H http) throws Exception {ApplicationContext context = http.getSharedObject(ApplicationContext.class);CorsFilter corsFilter = getCorsFilter(context);if (corsFilter == null) {throw new IllegalStateException("Please configure either a " + CORS_FILTER_BEAN_NAME + " bean or a "+ CORS_CONFIGURATION_SOURCE_BEAN_NAME + "bean.");}http.addFilter(corsFilter);}这段代码很好理解 , 就是在当前的 Spring Context 中找到一个 CorsFilter , 然后将它加入到 http 对象的 filters 中 。 由上面的 HttpSecurity.cors 方法可知 , 这里的 http 对象实际类型就是 HttpSecurity 。5.3.2 getCorsFilter 方法做了什么也许你会好奇 , HttpSecurity 要如何保证 CorsFilter 一定在 Spring Security 的 Filters 之前调用 。 但是在研究这个之前 , 我们先来看看同样重要的 getCorsFilter 方法 , 这里可以解答我们前面的一些疑问 。
private CorsFilter getCorsFilter(ApplicationContext context) {if (this.configurationSource != null) {return new CorsFilter(this.configurationSource);}boolean containsCorsFilter = context.containsBeanDefinition(CORS_FILTER_BEAN_NAME);if (containsCorsFilter) {return context.getBean(CORS_FILTER_BEAN_NAME, CorsFilter.class);}boolean containsCorsSource = context.containsBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME);if (containsCorsSource) {CorsConfigurationSource configurationSource = context.getBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME, CorsConfigurationSource.class);return new CorsFilter(configurationSource);}boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,context.getClassLoader());if (mvcPresent) {return MvcCorsFilter.getMvcCorsFilter(context);}return null;}这是 CorsConfigurer 寻找 CorsFilter 的全部逻辑 , 我们用人话来说就是: