文章目录
1.了解
1.1ProviderManager
ProviderManager管理了一个AuthenticationProvider列表,每个AuthenticationProvider都是一个认证器
ProviderManager 相当于代理了多个 AuthenticationProvider,他们的关系如下图:
1.2AuthenticationProvider
publicinterfaceAuthenticationProvider{Authenticationauthenticate(Authentication var1)throwsAuthenticationException;booleansupports(Class<?> var1);}
AuthenticationProvider
- authenticate方法来验证,就是验证用户身份
- supports用来判断当前AuthenicationProvider是否对应支持Authentication
1.3Parent
- 一个ProviderManager管理多个AuthenticationPorvider
- 每一个ProviderManager可以配置一个parent
- 如果当前的 ProviderManager 中认证失败了,还可以去它的 parent 中继续执行认证(一般还是ProviderManager)
AuthenticationManager 的初始化会分为两块,
一个全局的 AuthenticationManager,也就是 parent,另一个则是局部的 AuthenticationManager。
先给大家一个结论,一个系统中,我们可以配置多个 HttpSecurity(参见Spring Security 竟然可以同时存在多个过滤器链?),而每一个 HttpSecurity 都有一个对应的 AuthenticationManager 实例(局部 AuthenticationManager),这些局部的 AuthenticationManager 实例都有一个共同的 parent,那就是全局的 AuthenticationManager。
2.源码分析
AuthenticationManagerBuilder 源码比较长,我们来看几个关键的方法
publicclassAuthenticationManagerBuilderextendsAbstractConfiguredSecurityBuilder<AuthenticationManager,AuthenticationManagerBuilder>implementsProviderManagerBuilder<AuthenticationManagerBuilder>{publicAuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor){super(objectPostProcessor,true);}publicAuthenticationManagerBuilderparentAuthenticationManager(AuthenticationManager authenticationManager){if(authenticationManager instanceofProviderManager){eraseCredentials(((ProviderManager) authenticationManager).isEraseCredentialsAfterAuthentication());}this.parentAuthenticationManager = authenticationManager;returnthis;}publicInMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>inMemoryAuthentication()throwsException{returnapply(newInMemoryUserDetailsManagerConfigurer<>());}publicJdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder>jdbcAuthentication()throwsException{returnapply(newJdbcUserDetailsManagerConfigurer<>());}public<TextendsUserDetailsService>DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T>userDetailsService(T userDetailsService)throwsException{this.defaultUserDetailsService = userDetailsService;returnapply(newDaoAuthenticationConfigurer<>(
userDetailsService));}@OverrideprotectedProviderManagerperformBuild()throwsException{if(!isConfigured()){
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");returnnull;}ProviderManager providerManager =newProviderManager(authenticationProviders,
parentAuthenticationManager);if(eraseCredentials !=null){
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);}if(eventPublisher !=null){
providerManager.setAuthenticationEventPublisher(eventPublisher);}
providerManager =postProcess(providerManager);return providerManager;}}
步骤分析:
1.首先,我们调用parentAuthenticationManager 给AuthenticationManager 设置parent
2.inMemoryAuthentication、jdbcAuthentication 以及 userDetailsService 几个方法是配置数据源
3.performBuild方法,根据AuthenticationManagerBuilder构建AuthenticationManager
构建ProviderManager,一方面传入authenticationProviders(就是ProviderManager 管理的所有AuthenticationProvider),另一方面传入ProviderManager 的 parent(其实也是一个 ProviderManager)
2.1初始化
AuthenticationConfiguration ,这个类可以当做
@Configuration(proxyBeanMethods =false)@Import(ObjectPostProcessorConfiguration.class)publicclassAuthenticationConfiguration{@BeanpublicAuthenticationManagerBuilderauthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,ApplicationContext context){LazyPasswordEncoder defaultPasswordEncoder =newLazyPasswordEncoder(context);AuthenticationEventPublisher authenticationEventPublisher =getBeanOrNull(context,AuthenticationEventPublisher.class);DefaultPasswordEncoderAuthenticationManagerBuilder result =newDefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, defaultPasswordEncoder);if(authenticationEventPublisher !=null){
result.authenticationEventPublisher(authenticationEventPublisher);}return result;}@BeanpublicstaticGlobalAuthenticationConfigurerAdapterenableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context){returnnewEnableGlobalAuthenticationAutowiredConfigurer(context);}@BeanpublicstaticInitializeUserDetailsBeanManagerConfigurerinitializeUserDetailsBeanManagerConfigurer(ApplicationContext context){returnnewInitializeUserDetailsBeanManagerConfigurer(context);}@BeanpublicstaticInitializeAuthenticationProviderBeanManagerConfigurerinitializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context){returnnewInitializeAuthenticationProviderBeanManagerConfigurer(context);}publicAuthenticationManagergetAuthenticationManager()throwsException{if(this.authenticationManagerInitialized){returnthis.authenticationManager;}AuthenticationManagerBuilder authBuilder =this.applicationContext.getBean(AuthenticationManagerBuilder.class);if(this.buildingAuthenticationManager.getAndSet(true)){returnnewAuthenticationManagerDelegator(authBuilder);}for(GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers){
authBuilder.apply(config);}
authenticationManager = authBuilder.build();if(authenticationManager ==null){
authenticationManager =getAuthenticationManagerBean();}this.authenticationManagerInitialized =true;return authenticationManager;}@AutowiredpublicvoidsetApplicationContext(ApplicationContext applicationContext){this.applicationContext = applicationContext;}@AutowiredpublicvoidsetObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor){this.objectPostProcessor = objectPostProcessor;}privatestaticclassEnableGlobalAuthenticationAutowiredConfigurerextendsGlobalAuthenticationConfigurerAdapter{privatefinalApplicationContext context;privatestaticfinalLog logger =LogFactory.getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);EnableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context){this.context = context;}@Overridepublicvoidinit(AuthenticationManagerBuilder auth){Map<String,Object> beansWithAnnotation = context
.getBeansWithAnnotation(EnableGlobalAuthentication.class);if(logger.isDebugEnabled()){
logger.debug("Eagerly initializing "+ beansWithAnnotation);}}}}
一言以蔽之,AuthenticationConfiguration 中的配置有没有用上,全看开发者有没有重写
configure(AuthenticationManagerBuilder auth)
方法,重写了,就用 localConfigureAuthenticationBldr 来构建 parent 级别的 AuthenticationManager,没重写,就用 AuthenticationConfiguration 中的方法来构建。
版权归原作者 南一道街丶 所有, 如有侵权,请联系我们删除。