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
说明
2024-03-03 二刷,有点看不懂重新刷一次
总结一下,核心类有WebSecurity和HttpSecurty,还有我们自定义配置用的比较多的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(九)》
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; }