SpringBoot跨域加SpringSecurity就失效( 六 )

  • CorsConfigurer 自己是否有配置 CorsConfigurationSource , 如果有的话 , 就用它创建一个 CorsFilter 。
  • 在当前的上下文中 , 是否存在一个名为 corsFilter 的实例 , 如果有的话 , 就把他当作一个 CorsFilter 来用 。
  • 在当前的上下文中 , 是否存在一个名为 corsConfigurationSource 的 CorsConfigurationSource 实例 , 如果有的话 , 就用它创建一个 CorsFilter 。
  • 在当前上下文的类加载器中 , 是否存在类 HandlerMappingIntrospector , 如果有的话 , 则通过 MvcCorsFilter 这个内部类创建一个 CorsFilter 。
  • 如果没有找到 , 那就返回一个 null , 调用的地方最后会抛出异常 , 阻止 Spring 初始化 。
  • 上面的第 2、3、4 步能解答我们前面的配置为什么生效 , 以及它们的区别 。
    注册 CorsFilter 的方式 , 这个 Filter 最终会被直接注册到 Servlet container 中被使用到 。
    注册 CorsConfigurationSource 的方式 , 会用这个 source 创建一个 CorsFiltet 然后注册到 Servlet container 中被使用到 。
    而第四步的情况比较复杂 。 HandlerMappingIntrospector 是 Spring Web 提供的一个类 , 实现了 CorsConfigurationSource 接口 , 所以在 MvcCorsFilter 中 , 它被直接用于创建 CorsFilter 。 它实现的 getCorsConfiguration 方法 , 会经历:
    1. 遍历 HandlerMapping 。
    2. 调用 getHandler 方法得到 HandlerExecutionChain 。
    3. 从中找到 CorsConfigurationSource 的实例 。
    4. 调用这个实例的 getCorsConfiguration 方法 , 返回得到的 CorsConfiguration 。
    所以得到的 CorsConfigurationSource 实例 , 实际上就是前面讲到的 CorsInterceptor 或者 PreFlightHandler 。
    所以第四步实际上匹配的是实现 WebMvcConfigurer.addCorsMappings 方法的方式 。
    由于在 CorsFilter 中每次处理请求时都会调用 CorsConfigurationSource.getCorsConfiguration 方法 , 而 DispatcherServlet 中也会每次调用 HandlerMapping.getHandler 方法 , 再加上这时的 HandlerExecutionChain 中还有 CorsInterceptor , 所以使用这个方式相对于其他方式 , 做了很多重复的工作 。 所以 WebMvcConfigurer.addCorsMappings + HttpSecurity.cors 的方式降低了我们代码的效率 , 也许微乎其微 , 但能避免的情况下 , 还是不要使用 。
    5.3.3 HttpSecurity 中的 filters 属性在 CorsConfigurer.configure 方法中调用的 HttpSecurity.addFilter 方法 , 由它的父类 HttpSecurityBuilder 声明 , 并约定了很多 Filter 的顺序 。 然而 CorsFilter 并不在其中 。 不过在 Spring Security 中 , 目前还只有 HttpSecurity 这一个实现 , 所以我们来看看这里的代码实现就知道 CorsFilter 会排在什么地方了 。
    public HttpSecurity addFilter(Filter filter) {Class filterClass = filter.getClass();if (!comparator.isRegistered(filterClass)) {throw new IllegalArgumentException("...");}this.filters.add(filter);return this;}我们可以看到 , Filter 会被直接加到 List 中 , 而不是按照一定的顺序来加入的 。 但同时 , 我们也发现了一个 comparator 对象 , 并且只有被注册到了该类的 Filter 才能被加入到 filters 属性中 。 这个 comparator 又是用来做什么的呢?
    在 Spring Security 创建过程中 , 会调用到 HttpSeciryt.performBuild 方法 , 在这里我们可以看到 filters 和 comparator 是如何被使用到的 。
    protected DefaultSecurityFilterChain performBuild() throws Exception {Collections.sort(filters, comparator);return new DefaultSecurityFilterChain(requestMatcher, filters);}


    推荐阅读