慢慢来就很简单的security学习(四)源码阅读httpSecurity和AuthenticationManager

httpSecurity 的执行流程和 AuthenticationConfiguration 配置的 AuthenticationManager

0x00 回顾

webSecurity, httpSecurity 和 AuthenticationManagerBuilder 都继承了 AbstractSecurityBuilder<O>, 
也就是他们都是使用的设计模式里面的建造者模式各自创建的对象. 
webSecurity 被 WebSecurityConfiguration 控制创建了过滤链的代理, 
httpSecuity 被 webSecurity 控制创建了过滤链, 
AuthenticationManagerBuilder 被 AuthenticationConfiguration 控制, 创建了 AuthenticationManager;

值得注意的是, 在建造者设计模式里面产品, 建造者, 指挥者的关系. 指挥者设置建造者里面的参数, 调用建造者的 build 方法获取产品对象.    
在上篇讲的 webSecurity 里面, 这个关系是 :    
    webSecurityConfigutation 设置 webSecurity 的参数 (WebSecurityConfigurer<WebSecurity>), 
    调用 build() 方法获取 filterChainProxy 对象.
    这都是在 webSecurityConfigutation 类里面完成的.

在接下来要讲的 httpSecurity 里面, 也是这个类似的关系, 只是流程不是这么典型 : 
    webSecurity#build()#init() 执行的时候, 调用了他里面的 webSecurityConfigutation 类的 init() 方法. 
    并将创建好的 httpSeurity 对象放在 securityFilterChainBuilder 集合里面.
        此时创建了 httpSecurity 对象, 并且给 httpSecurity 对象设置了一些默认需要的过滤器配置, 
        这些过滤器配置会在 httpSecurity#build() 的时候创建过滤器并加入 filters 里面;
    在 webSecurity#build()#perfromBuild() 里面才会对每一个 httpSecurity 执行 build() 方法, 
    获取 httpSecurity 创建的 DefaultSecurityFilterChain 对象.

至于 AuthenticationManagerBuilder 在 AuthenticationConfiguration 里面清纯简单不做作的被创建个鬼啊. / 扶额
AuthenticationManagerBuilder 根据用户的使用情况, 是否重载了 configure(AuthenticationManagerBuilder auth) 方法, 
    1. 没有重载就是在 AuthenticationConfiguration#getAuthenticationManager() 方法里被创建, 这样会注入一些 bean.
    2. 重载了, 那就是在 WebSecurityConfigurer 里创建一个空的实例.
然后将 AuthenticationManager 设置进 httpSecurity 里, 当 httpSecurity 的配置文件执行 init() 方法的时候,
会根据这个 http_filter_configurer 配置文件的情况将 AuthenticationManagerBuilder 里设置配置值 (provider 的实现类).
最后在 beforeConfigure() 方法里 执行 build() 方法 构建 AuthenticationManager 实例.

0x01 从 WebSecurityConfigurerAdapter 里面的 getHttp() 开始

webSecurity#build()#init() 方法执行的时候, 调用 WebSecurityConfigurerAdapter 类的 init() 方法;
在 init() 里面 httpSecurity 被创建和初始化, 也被设置进 webSecurity;

// 不重要的方法略过
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
    
    
    // 这几个变量关系比较明确, 建造者设计模式
    private AuthenticationConfiguration authenticationConfiguration;
    private AuthenticationManagerBuilder authenticationBuilder;
    private AuthenticationManagerBuilder localConfigureAuthenticationBldr;
    private AuthenticationManager authenticationManager;

    public void init(final WebSecurity web) throws Exception {
    
    
        // 初始化了一个 http 对象, 
        final HttpSecurity http = getHttp();
        // 将 http 设置进 webSecurity. 
        web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
    
    
            public void run() {
    
    
                FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
                web.securityInterceptor(securityInterceptor);
            }
        });
    }

    protected final HttpSecurity getHttp() throws Exception {
    
    
        if (http != null) {
    
    
            return http;
        }

        DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
        localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);

        // 1, 这里获取鉴权管理 
        AuthenticationManager authenticationManager = authenticationManager();
        // 设置在父级里面, 此变量也是在 setObjectPostProcessor() 方法里被赋值
        authenticationBuilder.parentAuthenticationManager(authenticationManager);
        // 2, 创建共享对象
        Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();
        // 创建了一个 http 实例
        http = new HttpSecurity(objectPostProcessor, authenticationBuilder, sharedObjects);
        // 这就是默认被配置的过滤器链, 配置的顺序在别的地方有排序
        if (!disableDefaults) {
    
    
            // @formatter:off
            http
                .csrf().and()
                .addFilter(new WebAsyncManagerIntegrationFilter())
                .exceptionHandling().and()
                .headers().and()
                .sessionManagement().and()
                .securityContext().and()
                .requestCache().and()
                .anonymous().and()
                .servletApi().and()
                .apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()
                .logout();
            // @formatter:on
            ClassLoader classLoader = this.context.getClassLoader();

            // SpringFactoriesLoader 这个类实现了检索 META-INF/spring.factories 文件,并获取指定接口的配置的功能。
            // 这是 java spi 的约定, 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定
            List<AbstractHttpConfigurer> defaultHttpConfigurers =
                    SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
            // 如果有, 则加入 http 配置类里面.
            for(AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
    
    
                http.apply(configurer);
            }
        }
        // 调用被子类覆盖重写的方法, 这个方法也就是我们使用 spring security 的主要配置的方法啦
        configure(http);
        return http;
    }

    // 如果 #configure(AuthenticationManagerBuilder) 方法没被重载了, 就执行默认的 authenticationConfiguration;
    // 否则执行 localConfigureAuthenticationBldr.build(); 来获取 AuthenticationManager;
    protected AuthenticationManager authenticationManager() throws Exception {
    
    
        if (!authenticationManagerInitialized) {
    
    
            configure(localConfigureAuthenticationBldr);
            if (disableLocalConfigureAuthenticationBldr) {
    
    
                // authenticationConfiguration 此变量是直接被 spring ioc Autowire 设置的, 
                // 实例来自 AuthenticationConfiguration 的注入
                authenticationManager = authenticationConfiguration.getAuthenticationManager();
            } else {
    
    
                // localConfigureAuthenticationBldr 看下面的方法
                authenticationManager = localConfigureAuthenticationBldr.build();
            }
            authenticationManagerInitialized = true;
        }
        return authenticationManager;
    }

    // 这里就是 localConfigureAuthenticationBldr 被创建的时候, 也是直接 new 的
    // 为什么要说也? 因为 AuthenticationConfiguration 也是这么创建的. 只是设置了一些值
    @Autowired
    public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
    
    
        this.objectPostProcessor = objectPostProcessor;
        // 这个 authenticationBuilder 被设置进了 httpSecurity 里面
        authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);
        localConfigureAuthenticationBldr = new AuthenticationManagerBuilder(objectPostProcessor) {
    
    
            @Override
            public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
    
    
                authenticationBuilder.eraseCredentials(eraseCredentials);
                return super.eraseCredentials(eraseCredentials);
            }
        };
    }

    // 往 map 里面丢了一堆值, 以后要用就在里面取
    // Creates the shared objects
    private Map<Class<? extends Object>, Object> createSharedObjects() {
    
    
        Map<Class<? extends Object>, Object> sharedObjects = new HashMap<Class<? extends Object>, Object>();
        sharedObjects.putAll(localConfigureAuthenticationBldr.getSharedObjects());
        sharedObjects.put(UserDetailsService.class, userDetailsService());
        sharedObjects.put(ApplicationContext.class, context);
        sharedObjects.put(ContentNegotiationStrategy.class, contentNegotiationStrategy);
        sharedObjects.put(AuthenticationTrustResolver.class, trustResolver);
        return sharedObjects;
    }
}

小结

  • authenticationBuilder.parentAuthenticationManager(authenticationManager());
    • authenticationManager() 方法获取 AuthenticationManager 是根据用户的使用情况
    • 是否重载了 configure(AuthenticationManagerBuilder auth) 方法,
      1. 没有重载就是在 AuthenticationConfiguration#getAuthenticationManager() 方法里被创建, 这样会注入一些默认的 bean.
      2. 重载了, 那就是在 WebSecurityConfigurer 里创建一个空的实例, 然后执行 build().
  • 创建了一个 AuthenticationManager , 然后设置进 authenticationBuilder 的父管理里面了
  • 之后又把 authenticationBuilder 设置进了 httpSecurity 对象里面;

0x02 看一下 AuthenticationConfiguration 里面做了些什么

AuthenticationConfiguration 这个类的详细解析

@Configuration
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
    
    

    @Bean
    public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
    
    
        return new AuthenticationManagerBuilder(objectPostProcessor);
    }

    // 此方法就是上面调用的用于获取 AuthenticationManager 实例的方法
    public AuthenticationManager getAuthenticationManager() throws Exception {
    
    
        // 用原子布尔值, 同步
        if (this.authenticationManagerInitialized) {
    
    
            return this.authenticationManager;
        }
        // new 了一个实例
        AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(this.objectPostProcessor);
        if (this.buildingAuthenticationManager.getAndSet(true)) {
    
    
            return new AuthenticationManagerDelegator(authBuilder);
        }
        // 全局的鉴权配置
        // globalAuthConfigurers 是被 spring 控制注入的 List<GlobalAuthenticationConfigurerAdapter> 类型
        for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
    
    
            authBuilder.apply(config);
        }
        // 创建 authenticationManager 
        authenticationManager = authBuilder.build();

        // 如果获取不到, 就尝试懒加载实例
        if (authenticationManager == null) {
    
    
            authenticationManager = getAuthenticationManagerBean();
        }

        this.authenticationManagerInitialized = true;
        return authenticationManager;
    }

    private AuthenticationManager getAuthenticationManagerBean() {
    
    
        // 返回一个懒加载的代理对象
        return lazyBean(AuthenticationManager.class);
    }
}
  • 直接创建了 AuthenticationManagerBuilder, 导入了一些默认的 GlobalAuthenticationConfigurerAdapter 配置, 然后执行 build();
  • 而如果重载了 configure(AuthenticationManagerBuilder auth) 方法, 则是直接 new 的一个对象, 没有设置值, 直接 build();
  • 将这个值设置进了 AuthenticationManagerBuilder 的父管理里面了

0x03 AuthenticationManagerBuilder#build() 做了些什么

AuthenticationManagerBuilder 继承了 AbstractSecurityBuilder<O>, 也是一个构造器.
通过前面 webSecurity 的学习, 我们知道了, builder 的执行逻辑.     
    先将抽象类里面的 configurers 执行 init(), configurer() 方法, 然后执行 perfromBuild();    

只是不同的是, 目前, 也就是以上的 builder 里面 configurers 设置的值要么是默认的, 要么是没有的;     
当然我们目前获取的这个 authenticationManager, 被设置进了 builder 的 parentAuthenticationManager;
    AuthenticationManager authenticationManager = authenticationManager();
    authenticationBuilder.parentAuthenticationManager(authenticationManager);
 
然后这个 authenticationBuilder 被 httpSecurity 放在了共享变量里面;
后期在 configurer 里面会给它加入一些 provider

0x04 httpSecurity 的配置过程

以下是默认的 http 配置, 我们分析一下其中几个

http
    .csrf().and()
    .addFilter(new WebAsyncManagerIntegrationFilter())
    .exceptionHandling().and()
    .headers().and()
    .sessionManagement().and()
    .securityContext().and()
    .requestCache().and()   
    .servletApi().and()
    .apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()
    .logout();
  1. .anonymous().and()
  2. .addFilter(new WebAsyncManagerIntegrationFilter())
public final class HttpSecurity extends
        AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
        implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
    
    

    // 当执行 http.anonymous() 的时候, 就是向 httpSecurity 里面的 configurers 里面添加了一个配置对象
    // getOrApply() 方法就是, 如果有这个配置就返回实例
    // 如果没有, 就创建并添加这个配置到集合里, 然后放回实例
    public AnonymousConfigurer<HttpSecurity> anonymous() throws Exception {
    
    
        return getOrApply(new AnonymousConfigurer<HttpSecurity>());
    }
    // 其他方法也是大同小异,
    // 这个配置不就是全局的异常处理器嘛.
    public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {
    
    
        return getOrApply(new ExceptionHandlingConfigurer<HttpSecurity>());
    }

    // 应用一个 filter 过滤器, 这样应用必须要在 spring security 里面的 FilterComparator 有记录
    public HttpSecurity addFilter(Filter filter) {
    
    
        Class<? extends Filter> filterClass = filter.getClass();
        // 如果 filter 没有设置排序值
        if (!comparator.isRegistered(filterClass)) {
    
    
            throw new IllegalArgumentException(""); // 错误信息省略
        }
        this.filters.add(filter);
        return this;
    }

    // 不然的话, 只能使用 addFilterBefore(), 先将自定义的 filter 记录在 FilterComparator 里, 然后添加
    public HttpSecurity addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter) {
    
    
        comparator.registerBefore(filter.getClass(), beforeFilter);
        return addFilter(filter);
    }
}

至于 apply(configurer) 这就是在 AbstractConfiguredSecurityBuilder 里面定义的, 向 configuruers 添加配置的方法;

0x05 httpSecurity 的 configurer 配置, 都做了什么事情

我们把 AnonymousConfigurer 这个配置当例子讲一下

public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
            AbstractHttpConfigurer<AnonymousConfigurer<H>, H> {
    
    

    // 省略了一些方法, 他们的主要作用就是用来设置 (定制) 一些匿名登录用户的信息
    // 同时也配置了 AnonymousAuthenticationProvider 和 AnonymousAuthenticationFilter

    // 主要看着两个方法, 如果没有用户定制 authenticationProvider authenticationFilter 两个变量的实现类
    // 那就使用自己 new 的类
    @Override
    public void init(H http) throws Exception {
    
    
        if (authenticationProvider == null) {
    
    
            authenticationProvider = new AnonymousAuthenticationProvider(getKey());
        }
        if (authenticationFilter == null) {
    
    
            authenticationFilter = new AnonymousAuthenticationFilter(getKey(), principal, authorities);
        }
        // 这里后置加工, 和我们之前讲的差不多, 都是为了能让 spring ioc 容器管理自己 new 的 bean
        authenticationProvider = postProcess(authenticationProvider);
        // 注意这里!! 这里就是向 authenticationManager 里面添加了配置信息
        http.authenticationProvider(authenticationProvider);
    }

    // 这里向 httpSecurity 里面添加了 AnonymousAuthenticationFilter 
    @Override
    public void configure(H http) throws Exception {
    
    
        authenticationFilter.afterPropertiesSet();
        http.addFilter(authenticationFilter);
    }
}
  • 这个配置类的 init(), 和 configurer() 方法什么时候被调用呢;

    • 当 webSecurity 执行 build() 的时候, 执行了 httpSecurity 的 build() 方法
    • http.build() 执行的时候, 分别对设置的所有配置类执行他们自己的 init(), configueer(),
      • init() 只是初始化, 这里设置了 authenticationManager 的配置信息
      • configueer() 设置了 httpSecurity 构造的对象的信息.
        • 这步执行完成之后, httpSecurity 构造的对象的信息就全都设置好, 并且装载好了
        • perfromBuile() 只是根据这些配置信息实例化最终需要的对象就好了.
    • 然后执行 perfromBuile() 构造出所需对象;
  • httpSecurity 里面向 authenticationManager 添加配置的方法

public final class HttpSecurity extends
        AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
        implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
    
    

    public HttpSecurity(ObjectPostProcessor<Object> objectPostProcessor,
            AuthenticationManagerBuilder authenticationBuilder,
            Map<Class<? extends Object>, Object> sharedObjects) {
    
    

        super(objectPostProcessor);
        Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null");
        // 在这里将 authenticationBuilder 设置进了共享 map 里面
        setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder);
        for (Map.Entry<Class<? extends Object>, Object> entry : sharedObjects.entrySet()) {
    
    
            setSharedObject((Class<Object>) entry.getKey(), entry.getValue());
        }
        ApplicationContext context = (ApplicationContext) sharedObjects.get(ApplicationContext.class);
        this.requestMatcherConfigurer = new RequestMatcherConfigurer(context);
    }

    // 从共享对象里面拿了一个 AuthenticationManagerBuilder 的值, 并把它返回
    // 这个值就是我们最开始被设置了父权限工厂的那个对象, 
    // 当时执行构造方法, http = new HttpSecurity(objectPostProcessor, authenticationBuilder, sharedObjects); 
    // 将那个 buauthenticationBuilder 放在了共享的 map 里面
    public HttpSecurity authenticationProvider(AuthenticationProvider authenticationProvider) {
    
    
        getAuthenticationRegistry().authenticationProvider(authenticationProvider);
        return this;
    }

    private AuthenticationManagerBuilder getAuthenticationRegistry() {
    
    
        return getSharedObject(AuthenticationManagerBuilder.class);
    }

    public <C> C getSharedObject(Class<C> sharedType) {
    
    
        return (C) this.sharedObjects.get(sharedType);
    }

    // 注意这个方法, 等下将
    @Override
    protected void beforeConfigure() throws Exception {
    
    
        setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
    }
}

getAuthenticationRegistry().authenticationProvider(authenticationProvider);authenticationProvider() 方法在 AuthenticationManagerBuilder 里面, 此方法也只是向 authenticationProviders 里面添加了一个权限管理的 configure.

扫描二维码关注公众号,回复: 12569359 查看本文章
public class AuthenticationManagerBuilder 
    extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder>
    implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
    
    

    public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {
    
    
        this.authenticationProviders.add(authenticationProvider);
        return this;
    }

    // ProviderManager 实现了 AuthenticationManager 接口
    // 它使用 authenticationProviders, parentAuthenticationManager 初始化了一个 ProviderManager()
    // parentAuthenticationManager 就是我们一直说的 父权限管理
    @Override
    protected ProviderManager performBuild() throws Exception {
    
    
        if (!isConfigured()) {
    
    
            logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
            return null;
        }
        ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager);
        if (eraseCredentials != null) {
    
    
            providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
        }
        if (eventPublisher != null) {
    
    
            providerManager.setAuthenticationEventPublisher(eventPublisher);
        }
        providerManager = postProcess(providerManager);
        return providerManager;
    }
}

现在思路已经很明确了, 还记得上篇随便提了一下的 beforeConfigurer() 这个方法吗.
上面 AuthenticationManagerBuilder.build() 方法的调用就发生在 httpSecurity 的这个方法里面
所以这样就构造了一个 AuthenticationManager 对象.

    @Override
    protected void beforeConfigure() throws Exception {
    
    
        setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
    }

0x06 从头梳理一下整个的流程 (将上一章结尾的流程细化)

细化的 (新加的) 流程我用 - [num] 标记

- 从 WebSecurityConfiguration 类的 setFilterChainProxySecurityConfigurer() 方法说起;
    - 在参数上的 sqel 表达式, 收集到应用环境里面所有的 WebSecurityConfigurer, 
        - 将他设置进 SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurers 参数里面
    - new 一个 webSecurity 对象, 并用 objectPostProcessor 处理, 让他具有和被 ioc 持有的 bean 一样的性质
    - 将 webSecurityConfigurers 进行排序, 如果排序值相同就报错
    - 依次将 webSecurityConfigurers 里面的每一个 WebSecurityConfigurer 设置进 WebSecurity 里面;
        - 将 WebSecurityConfigurer 设置进 WebSecurity 调用了它的 apply() 方法
        - 也就是将 WebSecurityConfigurer 设置到 AbstractConfiguredSecurityBuilder 的 configurers 里面
        - configurers 的类型是 LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>
    - 最后将 WebSecurityConfiguration 类的 webSecurityConfigurers 属性赋值

- springSecurityFilterChain() 返回一个'springSecurityFilterChain'
    - 查看 WebSecurityConfiguration 类的 webSecurityConfigurers 是否有值
        - 没有的话, 就向 WebSecurity 里 apply() 一个默认的 WebSecurityConfigurer
    - 执行 webSecurity 的 build() 方法
        - 执行 doBuild() 保证对象是单例的
            - 执行 init() 方法
                - 执行 configurers 里每一个 configurer 的 init(B builder) 方法
                    - configurer#init(B builder) 方法传入的就是在上面创建的 WebSecurity 对象
                    - WebSecurityConfigurerAdapter#init(WebSecurity web) 将会用 getHttp() 初始化一个 httpSecurity 对象
                        - [0] getHttp() 返回了一个 httpSecurity 实例
                            - [1] 获取一个 authenticationManager 并设置进 authenticationBuilder 的父权限管理里面
                                // 这里也是建造者模式, 流程相识, 不详细介绍
                                - [1.1] 如果 configure(authenticationManagerBuilder auth) 被重写覆盖了
                                    - authenticationManager 是从 AuthenticationConfiguration#getAuthenticationManager() 方法获取的对象;
                                - [1.2] 如果没有, 则是一个没有配置属性, 直接 build() 返回的 authenticationManager
                            - [2] 创建了共享变量 sharedObjects
                            - [3] httpSecurity = new HttpSecurity(objectPostProcessor, authenticationBuilder, sharedObjects);
                            - [4] 使用. anonymous().and() 等方式, 向 httpSecurity 实例里添加配置
                            - [5] 根据 java spi 规则, 向 httpSecurity 实例里添加配置
                            - [6] 执行被我们继承重写的 configure(HttpSecurity http) 方法
                    - 并把 httpSecurity 对象 设置进 web(也就是前面创建的 webSecurity) 的 securityFilterChainBuilders 属性里面
                    - 获取 httpSecurity 里 FilterSecurityInterceptor 类型的共享对象, 设置进 webSecurity 里面
            - 执行 configure() 方法
                - 执行 configurers 里每一个 configurer 的 configure(B builder) 方法
                    - WebSecurityConfigurerAdapter#configure(WebSecurity web) 默认空方法, 一般用于设置需要忽略的请求
                    - 也就是往 ignoredRequests 里面加 RequestMatcher
            - 执行 performBuild() 方法
                - 创建一个 securityFilterChains, 类型是 List<SecurityFilterChain>
                - 遍历 webSecurity 的 ignoredRequests, 创建匹配不处理路径的 SecurityFilterChain, 将他加入 securityFilterChains
                - 遍历 securityFilterChainBuilders(也就是所有 httpSecurity 对象), 执行 httpSecurit 的 build(), 将返回的值加入 securityFilterChains
                    - httpSecurity#build(), 这个方法返回一个过滤器链 DefaultSecurityFilterChain(requestMatcher, filters)
                    - requestMatcher 是 uri 的匹配规则, 默认的 AnyRequestMatcher.INSTANCE;
                    - filters 是一组利用 http.and() 加入的过滤器 List<Filter> filters = new ArrayList<Filter>();
                        - [0] build() 方法依次执行 init(), beforeConfigure(), performBuild()
                            - [1] init() 方法, 将 httpSecurity 里面的配置初始化,configure() 做准备;
                                - [1.1] 我们知道 security 流程里, filter 和 provider 配合使用的, 
                                - [1.2] 这一步就是把这个 filter 对应的 provider 加入了 authenticationManagerBuilder 里, 不是加了一个 provider 配置
                            - [2] beforeConfigure() 这步调用 authenticationManagerBuilder 的 build() 创建了一个 authenticationManager 并加入共享变量里
                            // 这步完成后, 我们就可以用这个方法来授权了 this.getAuthenticationManager().authenticate(customToken);
                            - [3] performBuild() 返回了 SecurityFilterChain
                - 用 securityFilterChains 创建一个 FilterChainProxy 对象
                - 设置 filterChainProxy 的一些属性, 转型为 Filter, 并将它返回 (这也就是我们的目标'springSecurityFilterChain' )

还有一些常用对象比如 UserDetailsService, BCryptPasswordEncoder 等, 也大同小异, 在哪里创建了配置然后 apply 进去, 主要流程是这样的
对于一个请求来了的具体过滤执行流程很简单, 但是不想写了

然后 OAuth2 之类的, 不太熟练, 就放弃啦~;

0x07 balabalabala…

AuthenticationManageRBuilder 的初始化和配置过程, 并不是很清晰.
而且大佬设计框架的时候, 提前留空了 beforeConfigure() 感觉很神奇;
AbstractConfiguredSecurityBuilder 类和 SecurityConfigurer<O, B> 这个接口组合在一起, 是真的代码复用到爆炸
只能说, 给大佬跪了, orz, 作为菜鸡的我还有好长的路要走;
学习一个

//  abcdefghijklmnopqrstovwxyz

猜你喜欢

转载自blog.csdn.net/miyahejuzi/article/details/100081116