spring-security源码-初始化(九)

时序图

 

@startuml
participant "security starter" as sb
participant "WebSecurityConfiguration" as wc
participant "webSecurity" as ws
participant "WebSecurityConfigurerAdapter" as wa
participant "HttpSecurity" as hs

autonumber
==security初始化==
activate sb
sb->>sb:starter触发加载SecurityAutoConfiguration到spring容器
sb->>sb:SecurityAutoConfiguration@Import加载WebSecurityConfiguration\n到容器进行生命周期初始化

sb->>wc: spring生命周期触发setFilterChainProxySecurityConfigurer
deactivate sb
alt WebSecurityConfiguration.setFilterChainProxySecurityConfigurer
activate wc
wc->>wc: 通过形参注入获取容器中WebSecurityConfigurerAdapter
wc->>wc: 执行排序后加入到成员变量webSecurity
end
deactivate wc

activate sb
sb->>wc: spring生命周期触发springSecurityFilterChain
deactivate sb

alt WebSecurityConfiguration.springSecurityFilterChain
activate wc
wc->>wc: 从已有filterChain获取实现了FilterSecurityInterceptor\n加入到webSecurity.securityInterceptor
wc->>wc: 从容器获取webSecurityCustomizers\n执行回调获取到webSecurity做定制化操作
wc->>ws: 执行webSecurity.build方法
deactivate wc

activate ws

activate wa
alt configurers就是我们的adapter
ws->>wa : 执行init()遍历configurers调用init方法传入this
alt 构建HttpSecurity
wa->>wa : 获取从容器获取事件广播AuthenticationEventPublisher(支持自定义)
wa->>wa : 构建authenticationManager主要做登录认证(支持自定义)
wa->>wa : spi方式获取AbstractHttpConfigurer(也就是filter过滤器的建造者,通过它可以自定义filter)
wa->>wa : 构建 HttpSecurity(filterChain构建建造者)
wa->>wa : 执行configure()传入 HttpSecurity,也就是为什么我们可以在adapter子类中重写configure方法\n获取到HttpSecurity进行定制化设置
wa->>ws : HttpSecurity建造者加入到webSecurity[web.addSecurityFilterChainBuilder(http)]
end

ws->>wa : 执行beforeConfigure 空实现钩子方法
ws->>wa : 执行configure() 遍历configurers调用configure方法传入this\n可以通过这个钩子方法获取到webSecurity
ws->>hs : 执行performBuild() 遍历HttpSecurity的build方法构建SecurityFilterChain list
activate hs
ws->>ws : 将SecurityFilterChain list交给FilterChainProxy统一管理\nFilterChainProxy就是security的servlet filter入口
deactivate hs
end
deactivate ws
deactivate wa
end

@enduml
View Code

 

说明

2024-03-03 二刷,有点看不懂重新刷一次

总结一下,核心类有WebSecurityHttpSecurty,还有我们自定义配置用的比较多的WebSecurityConfigurerAdapter

1.首先明确我们完成自定义配置configure都是使用的WebSecurityConfigurerAdapter

2.在初始化WebSecurity会从容器获取到所有WebSecurityConfigurerAdapter,调用其init方法生成SecurityFilterChainBuilder,其实他就是HttpSecurty的父类,所以就是HttpSecurty

3.WebSecurity会循环调用WebSecurityConfigurerAdapter 调用其configure传入HttpSecurty也就是init方法生成的SecurityFilterChainBuilder,其实就是建造者模式,我们自定义才可以他通过...来配置

比如

 http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login.html")//登录页面路径
                .loginProcessingUrl("/doLogin")
                .usernameParameter("loginName")
                .passwordParameter("loginPassword")
                .defaultSuccessUrl("/index")
                .successForwardUrl("/index")
                .permitAll()//不拦截
                .and()
                .csrf()//记得关闭
                .disable();

其实我们每.一个就会内部生成一个config,对应一个filter的生成规则

 

3.最后WebSecurity通过遍历SecurityFilterChainBuilder builder负责生成一批filter,封装成SecurityFilterChain

4. "springSecurityFilterChain"; 最后通过org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration 注入到Servle

使用spring-boot 我们引入security的包 就可以自动实现简单的登录,是怎么做到的呢?

知道spring-security源码,我们的可以通过打断点方式,找到各个核心源码处,知道各个配置原理,和扩展点 完成业务定制化逻辑

 

security自动化配置

1.在spring-boot-autoconfigure的spring.factories引入了security的自动化配置。我们主要看最核心的org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration

spriing自动化配置原理可以参考《Spring Boot-Starter(九)》

 

org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;

 

2.SecurityAutoConfiguration实现

Import导入原理可以参考《spring源码阅读(五)-Spring Import注解使用》《Spring源码阅读(六)-ConfigurationClassPostProcessor》

这里简单描述一下,import导入会将import相关类交给spring容器管理,通过spring生命周期开始了初始化流程,详情看上面原理

@Configuration(
        proxyBeanMethods = false
)
@ConditionalOnClass({DefaultAuthenticationEventPublisher.class})//class path有此类加载
@EnableConfigurationProperties({SecurityProperties.class})
//Import导入 我们主要看WebSecurityEnablerConfiguration
@Import({SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class, SecurityDataConfiguration.class})
public class SecurityAutoConfiguration {
    public SecurityAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean({AuthenticationEventPublisher.class})//容器没有这个bean触发加载
    public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
        return new DefaultAuthenticationEventPublisher(publisher);
    }
}

3.我们继续看核心初始化的EnableWebSecurity

@Configuration(
        proxyBeanMethods = false//不需要代理
)
@ConditionalOnBean({WebSecurityConfigurerAdapter.class})//容器中有WebSecurityConfigurerAdapter对象触发自动加载,我们经常配置就是用这个类
@ConditionalOnMissingBean(//容器中不能出现springSecurityFilterChain的实例,因为config本质就是为了初始化chain,如果有表示用户自定义了 
        name = {"springSecurityFilterChain"}
)
@ConditionalOnWebApplication(
        type = ConditionalOnWebApplication.Type.SERVLET
)
@EnableWebSecurity//组合注解,里面还有import导入类
public class WebSecurityEnablerConfiguration {
    public WebSecurityEnablerConfiguration() {
    }
}

4.这里又用到了Import导入 我们主要看核心初始化逻辑WebSecurityConfiguration

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
        HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {

    /**
     * Controls debugging support for Spring Security. Default is false.
     * @return if true, enables debug support with Spring Security
     */
    boolean debug() default false;

}

5.WebSecurityConfiguration类已经是走spring生命周期初始化了首先调用@Autowired的setFilterChainProxySecurityConfigurer

这个方法。首先会初始化一个webSecurity注入我们定义的WebSecurityConfigurerAdapter子类,后续走我们的自定义扩展配置用

org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration#setFilterChainProxySecurityConfigurer

  /**
     *autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()
     * set注入WebSecurityConfigurer的实现 也就是我们的配置的WebSecurityConfigurerAdapter子类集合
     */
    @Autowired(required = false)
    public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
                                                      @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
            throws Exception {
        //这里是通过new创建WebSecurity  同时通过objectPostProcessor,完成对象的依赖注入,比如这个类里面有spring注入注解
        //我们可以阅读里面成员变量原理 通过容器注入对应对象完成初始化复制
        this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
        if (this.debugEnabled != null) {
            this.webSecurity.debug(this.debugEnabled);
        }
        //对我们dapter实现排序
        webSecurityConfigurers.sort(WebSecurityConfiguration.AnnotationAwareOrderComparator.INSTANCE);
        Integer previousOrder = null;
        Object previousConfig = null;
        for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
            Integer order = WebSecurityConfiguration.AnnotationAwareOrderComparator.lookupOrder(config);
            if (previousOrder != null && previousOrder.equals(order)) {
                throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order
                        + " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
            }
            previousOrder = order;
            previousConfig = config;
        }
        //循环遍历设置到 add 到webSecurity成员变量configurers 
        for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
            this.webSecurity.apply(webSecurityConfigurer);
        }
        this.webSecurityConfigurers = webSecurityConfigurers;
    }

6.

这里主要是根据adapter的配置初始化springSecurityFilterChain,这里面管理Filter集合

public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain"; 最后通过org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration 注入到Servlet

org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration#springSecurityFilterChain

 @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    public Filter springSecurityFilterChain() throws Exception {
        boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
        boolean hasFilterChain = !this.securityFilterChains.isEmpty();
        Assert.state(!(hasConfigurers && hasFilterChain),
                "Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
        //我们没有配置 这里应该是配置一个默认的
        if (!hasConfigurers && !hasFilterChain) {
            WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
                    .postProcess(new WebSecurityConfigurerAdapter() {
                    });
            this.webSecurity.apply(adapter);
        }

        /**
         * securityFilterChains 是通过容器获取 通过@Autowired set方法注入
         * 这里也是一个扩展点 我们可以增加手动增加securityFilterChain
* 如果容器有SecurityFilterChain,则将filter提取出来统一暴露,比如我们想直接自定义SecurtyFiitler就通过这个,比如写一个TokenFilter
*/ for (SecurityFilterChain securityFilterChain : this.securityFilterChains) { this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain); for (Filter filter : securityFilterChain.getFilters()) { //如果这个filter是FilterSecurityInterceptor 则加入到securityInterceptor if (filter instanceof FilterSecurityInterceptor) { this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter); break; } } } /** * webSecurityCustomizers也是从容器获取 * 也是一个扩展点。我们可以自定义 在build前对webSecurity做一些定制化操作 * @通过@Autowired set方法注入 比如我们想获得webSecurity做一些些的操作,比如手动增加filter */ for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) { customizer.customize(this.webSecurity); } /* *<1>执行build webSecurity管理者我们的Adapter */ return this.webSecurity.build(); }

<1>

模板模式

org.springframework.security.config.annotation.AbstractSecurityBuilder#build

    @Override
    public final O build() throws Exception {
        if (this.building.compareAndSet(false, true)) {
            //<2>模板模式
            this.object = doBuild();
            return this.object;
        }
        throw new AlreadyBuiltException("This object has already been built");
    }

<2>

所有配置都继承这个类

org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#doBuild

 /**
     * @return
     * @throws Exception
     */
    @Override
    protected final O doBuild() throws Exception {
        synchronized (this.configurers) {
            this.buildState = AbstractConfiguredSecurityBuilder.BuildState.INITIALIZING;
            //空实现
            beforeInit();
            //<6>
            init();
            this.buildState = AbstractConfiguredSecurityBuilder.BuildState.CONFIGURING;
            beforeConfigure();
            //<4>
            configure();
            this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILDING;
//模板方法 抽象的子类必须实现 真正的build方法<10> O result
= performBuild(); this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILT; return result; } }

针对不同的build会调用不同的performBuild方法

<3>

org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#init

@SuppressWarnings("unchecked")
    private void init() throws Exception {
        //获得configures调用configures的init 注意不同的配置类 就是调用不同配置的init方法
        Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
        for (SecurityConfigurer<O, B> configurer : configurers) {
            configurer.init((B) this);
        }
        for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {
            configurer.init((B) this);
        }
    }

针对不同配置 Configurers不一样,如果是WebSecurity则getConfigures是 WebSecurityConfigurerAdapter 所以调用的WebSecurityConfigurerAdapter的init方法<6> 我们可以在webAdapter重新init方法

<4>

org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#configure

    @SuppressWarnings("unchecked")
    private void configure() throws Exception {
        Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
        for (SecurityConfigurer<O, B> configurer : configurers) {
            //不同的配置类就是调用不同的 configure方法初始化
            configurer.configure((B) this);
        }
    }

针对不同配置 Configurers不一样

1.如果是WebSecurity则getConfigures是 WebSecurityConfigurerAdapter 所以调用的WebSecurityConfigurerAdapter的configure方法<5> 也就是我们的Adapter配置点

2.如果是HttpSecurity则是<11>处配置的各种config如 如果有需要可以研究各个config如何初始化的比如我们参考HeaderConfigure的实现<12>

3.针对DefaultPasswordEncoderAuthenticationManagerBuilder 的confgure请看<15>

<15>

 

 

<5>

一般我们都会重写

   @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");
    }

 

<6>

org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#init

 @Override
    public void init(WebSecurity web) throws Exception {
        //<7>初始化HttpSecurity
        HttpSecurity http = getHttp();
        //将HttpSecurity add 到WebSecurity
        web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
            FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
            web.securityInterceptor(securityInterceptor);
        });
    }

<7>

org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#getHttp

    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected final HttpSecurity getHttp() throws Exception {
        if (this.http != null) {
            return this.http;
        }
        //从容器获取AuthenticationEventPublisher
        AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();
        //设置到localConfigureAuthenticationBldr build
        this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
        //<8>通过localConfigureAuthenticationBldr build初始化AuthenticationManager 这里是org.springframework.security.authentication.ProviderManager
        AuthenticationManager authenticationManager = authenticationManager();
        //给authenticationBuilder 设置authenticationManager
        this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
        Map<Class<?>, Object> sharedObjects = createSharedObjects();
        //初始化HttpSecurity
        this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
        if (!this.disableDefaults) {
            //<11>进行默认配置
            applyDefaultConfiguration(this.http);
            ClassLoader classLoader = this.context.getClassLoader();
            List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
                    .loadFactories(AbstractHttpConfigurer.class, classLoader);
            for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
                this.http.apply(configurer);
            }
        }
        /**
         * <9>传入我们的http build 让我们可以做定制化配置
         *  @Override
         *     protected void configure(HttpSecurity http) throws Exception{
         *       ....
         *     }
         */
        configure(this.http);
        return this.http;
    }

 

<8>

org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#authenticationManager

    protected AuthenticationManager authenticationManager() throws Exception {
        //避免重复初始化
        if (!this.authenticationManagerInitialized) {
            /**
             * 这里就是调用自定义继承WebSecurityConfigurerAdapter重写的configure(AuthenticationManagerBuilder auth)
             * 传入build 让我们可以自定义一些参数配置 比如配置用户信息是基于应用 还是内存
             *  auth.inMemoryAuthentication()
             *                 .withUser("liqiang").password("liqiang").roles("admin")
             *                 .and()
             *                 .withUser("admin").password("admin").roles("admin");
             */
            configure(this.localConfigureAuthenticationBldr);
            //
            if (this.disableLocalConfigureAuthenticationBldr) {
                //这里是一个扩展点我们可以直接 authenticationConfiguration是根据spring容器初始化的 根据authenticationConfiguration而不是通过build
                this.authenticationManager = this.authenticationConfiguration.getAuthenticationManager();
            }
            else {
                //正常是走得这个build方法 build authenticationManager  这里会调用<1> 为何到1请看下面说明
                //默认 localConfigureAuthenticationBldr是DefaultPasswordEncoderAuthenticationManagerBuilder
                //初始化处 详看:<14>
                this.authenticationManager = this.localConfigureAuthenticationBldr.build();
            }
            this.authenticationManagerInitialized = true;
        }
        return this.authenticationManager;
    }

 

 

configure(this.localConfigureAuthenticationBldr);

这里需要强调的一点是调用我们继承的WebSecurityConfigurerAdapter 我们可以定义用户管理器

如基于应用内存

内部创建inMemoryAuthentication方法 创建InMemoryUserDetailsManagerConfigurer 到build confgures

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**
         *  inMemoryAuthentication 开启在内存中定义用户
         *  多个用户通过and隔开
         */
        auth.inMemoryAuthentication()
                .withUser("liqiang").password("liqiang").roles("admin")
                .and()
                .withUser("admin").password("admin").roles("admin");
    }

自定义userDetail

内部创建DaoAuthenticationConfigurer 到build confgures

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**
         *  inMemoryAuthentication 开启在内存中定义用户
         *  多个用户通过and隔开
         */
        auth.userDetailsService(new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
                return null;
            }
        });
    }

基于封装的jdbc查询jdbcAuthentication方法 创建JdbcUserDetailsManagerConfigurer 到build confgures

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**
         *  inMemoryAuthentication 开启在内存中定义用户
         *  多个用户通过and隔开
         */
        auth.jdbcAuthentication().dataSource(null).usersByUsernameQuery("");
    }

他们本质都是根据auth.创建不同的config对象 设置到build的configures  

 

<9>

    /**
     * 对于不需要授权的静态文件放行
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");
    }

<10>

org.springframework.security.config.annotation.web.builders.WebSecurity#performBuild

securityFilterChains为什么是列表

因为不同的url可以有不同的处理逻辑,可以参考一套Spring-Security基于源码扩展-一套系统多套登录逻辑(二十二)

FilterChainProxy实现了ServletFilter

  @Override
    protected Filter performBuild() throws Exception {
        Assert.state(!this.securityFilterChainBuilders.isEmpty(),
                () -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
                        + "Typically this is done by exposing a SecurityFilterChain bean "
                        + "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
                        + "More advanced users can invoke " + WebSecurity.class.getSimpleName()
                        + ".addSecurityFilterChainBuilder directly");
        /**
         * 得我们设置的忽略检查为他们添加一个 这里会添加3个chains 根据匹配做不通过处理
         *  public void configure(WebSecurity web) throws Exception {
         *         web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");
         *     }
         */
        int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
        List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
        for (RequestMatcher ignoredRequest : this.ignoredRequests) {
            securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
        }
        //securityFilterChainBuilders,通过我们配置的httpSecurity遍历生成
        for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
            //执行build遍历httpSecurityConfig生成filter<1> 最终会构建成DefaultSecurityChain描述哪些url能够这这一批filter<13> 
            securityFilterChains.add(securityFilterChainBuilder.build());
        }
        //通过FilterChainProxy 代理管理 它实现了ServletFilter 通过FilterChainProxy为Servlet入口 进入security的自己的filter
        FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
        if (this.httpFirewall != null) {
            filterChainProxy.setFirewall(this.httpFirewall);
        }
        if (this.requestRejectedHandler != null) {
            filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
        }
        filterChainProxy.afterPropertiesSet();

        Filter result = filterChainProxy;
        if (this.debugEnabled) {
           
            result = new DebugFilter(filterChainProxy);
        }
        this.postBuildAction.run();
        //返回filter 我们请求都会到filterChainProxy  通过他调用security的filter实现securityfilter 注入逻辑
        return result;
    }

<11>

org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#applyDefaultConfiguration

  private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
        //http本质也是build 这里都是配置默认的config configure add CsrfConfigurer
        http.csrf();
        //默认增加一个WebAsyncManagerIntegrationFilter
        http.addFilter(new WebAsyncManagerIntegrationFilter());
        //configures add ExceptionHandlingConfigurer
        http.exceptionHandling();
        //configures add HeadersConfigurer
        http.headers();
        //configures add SessionManagementConfigurer
        http.sessionManagement();
        //configure add SecurityContextConfigurer
        http.securityContext();
        //configure add RequestCacheConfigurer
        http.requestCache();
        ///configure add AnonymousConfigurer
        http.anonymous();
        ///configure add ServletApiConfigurer
        http.servletApi();
        //自定义默认config
        http.apply(new DefaultLoginPageConfigurer<>());
        //configure LogoutConfigurer
        http.logout();
    }

<12>

org.springframework.security.config.annotation.web.configurers.HeadersConfigurer#configure

   @Override
    public void configure(H http) {
        //创建一个HeaderFilter
        HeaderWriterFilter headersFilter = createHeaderWriterFilter();
        //添加到HttpSecurityFilter
        http.addFilter(headersFilter);
    }

<13>

org.springframework.security.config.annotation.web.builders.HttpSecurity#performBuild

@Override
    protected DefaultSecurityFilterChain performBuild() {
        //将httpSecurity filter排序
        this.filters.sort(OrderComparator.INSTANCE);
        List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
        for (Filter filter : this.filters) {
            sortedFilters.add(((OrderedFilter) filter).filter);
        }
        //requestMatcher 为匹配条件  DefaultSecurityFilterChain 包装起来 管理所有Filter
        return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
    }

<14>

org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#setApplicationContext

@Autowired
    public void setApplicationContext(ApplicationContext context) {
        this.context = context;
        ObjectPostProcessor<Object> objectPostProcessor = context.getBean(ObjectPostProcessor.class);
        LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(context);
        this.authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor,
                passwordEncoder);
        this.localConfigureAuthenticationBldr = new DefaultPasswordEncoderAuthenticationManagerBuilder(
                objectPostProcessor, passwordEncoder) {

            @Override
            public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
                WebSecurityConfigurerAdapter.this.authenticationBuilder.eraseCredentials(eraseCredentials);
                return super.eraseCredentials(eraseCredentials);
            }

            @Override
            public AuthenticationManagerBuilder authenticationEventPublisher(
                    AuthenticationEventPublisher eventPublisher) {
                WebSecurityConfigurerAdapter.this.authenticationBuilder.authenticationEventPublisher(eventPublisher);
                return super.authenticationEventPublisher(eventPublisher);
            }

        };
    }

<15>

跟WebSecurityConfigurerAdapter 一样 以下3个方法都是add不同的config 执行不同的初始化逻辑

static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder {

        private PasswordEncoder defaultPasswordEncoder;

        /**
         * Creates a new instance
         * @param objectPostProcessor the {@link ObjectPostProcessor} instance to use.
         */
        DefaultPasswordEncoderAuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
                PasswordEncoder defaultPasswordEncoder) {
            super(objectPostProcessor);
            this.defaultPasswordEncoder = defaultPasswordEncoder;
        }

        @Override
        public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
                throws Exception {
            return super.inMemoryAuthentication().passwordEncoder(this.defaultPasswordEncoder);
        }

        @Override
        public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
            return super.jdbcAuthentication().passwordEncoder(this.defaultPasswordEncoder);
        }

        @Override
        public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
                T userDetailsService) throws Exception {
            return super.userDetailsService(userDetailsService).passwordEncoder(this.defaultPasswordEncoder);
        }

    }

<16>

org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder#performBuild

    @Override
    protected ProviderManager performBuild() throws Exception {
        if (!isConfigured()) {
            this.logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
            return null;
        }
        //通过ProviderManager 统一管理providers authenticationProviders 都可以定制
        ProviderManager providerManager = new ProviderManager(this.authenticationProviders,
                this.parentAuthenticationManager);
        if (this.eraseCredentials != null) {
            providerManager.setEraseCredentialsAfterAuthentication(this.eraseCredentials);
        }
        if (this.eventPublisher != null) {
            providerManager.setAuthenticationEventPublisher(this.eventPublisher);
        }
        //依赖注入
        providerManager = postProcess(providerManager);
        return providerManager;
    }

 

posted @ 2021-11-04 15:04  意犹未尽  阅读(1423)  评论(0编辑  收藏  举报