前言
记录一次开发中遇到的问题,自定义了多个AuthenticationProvider,调试过程中居然找不到,发现ProviderManager的providers属性值中没有注入。经过排查,最终找到了原因,问题就出在AuthenticationManager的初始化上。自定义了多个AuthenticationProvider后,AuthenticationManager初始化出现了问题。
- 在Spring Security中认证功能主要由AuthenticationManager完成,但是这是一个接口,主要由其实现类ProviderManager认证完成,接下来主要介绍AuthenticationManager的创建初始化流程。
public interface AuthenticationManager {
Authentication authenticate(Authentication var1) throws AuthenticationException;
}
- @EnableWebSecurity 注解, 主要看@EnableGlobalAuthentication注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class})
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
- @EnableGlobalAuthentication,主要导入AuthenticationConfiguration这个类,重要看着一点
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({AuthenticationConfiguration.class})
@Configuration
public @interface EnableGlobalAuthentication {
}
- 接下来分析AuthenticationConfiguration,首先简单的了解一下过程
AuthenticationConfiguration中收集所有GlobalAuthenticationConfigurerAdapter类型的Bean并保存到globalAuthConfigurers中;
AuthenticationConfiguration中创建AuthenticationManagerBuilder类型的实例对象DefaultPasswordEncoderAuthenticationManagerBuilder;
将globalAuthConfigurers里面的对象传递给AuthenticationManagerBuilder;
执行AuthenticationManagerBuilder的build()方法完成AuthenticationManager的构建;
WebSecurityConfigurerAdapter中调用AuthenticationConfiguration的getAuthenticationManager()方法得到构建的AuthenticationManager类似对象;
@Configuration
@Import({ObjectPostProcessorConfiguration.class})
public class AuthenticationConfiguration {
private AtomicBoolean buildingAuthenticationManager = new AtomicBoolean();
private ApplicationContext applicationContext;
private AuthenticationManager authenticationManager;
private boolean authenticationManagerInitialized;
private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigurers = Collections.emptyList();
private ObjectPostProcessor<Object> objectPostProcessor;
public AuthenticationConfiguration() {
}
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
//构建AuthenticationManagerBuilder Bean对象
return new AuthenticationManagerBuilder(objectPostProcessor);
}
@Bean
public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
return new EnableGlobalAuthenticationAutowiredConfigurer(context);
}
//初始化DaoAuthenticationProvider,UserDetailsService和PasswordEncoder(后面会详细讲)
@Bean
public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) {
return new InitializeUserDetailsBeanManagerConfigurer(context);
}
//初始化AuthenticationProvider(后面会详细讲)
@Bean
public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context) {
return new InitializeAuthenticationProviderBeanManagerConfigurer(context);
}
//创建AuthenticationManager,该方法在WebSecurityConfigurerAdapter中被调用
public AuthenticationManager getAuthenticationManager() throws Exception {
if (this.authenticationManagerInitialized) {
return this.authenticationManager;
} else {
AuthenticationManagerBuilder authBuilder = this.authenticationManagerBuilder(this.objectPostProcessor);
if (this.buildingAuthenticationManager.getAndSet(true)) {
return new AuthenticationManagerDelegator(authBuilder);
} else {
Iterator var2 = this.globalAuthConfigurers.iterator();
while(var2.hasNext()) {
GlobalAuthenticationConfigurerAdapter config = (GlobalAuthenticationConfigurerAdapter)var2.next();
authBuilder.apply(config);
}
this.authenticationManager = (AuthenticationManager)authBuilder.build();
if (this.authenticationManager == null) {
this.authenticationManager = this.getAuthenticationManagerBean();
}
this.authenticationManagerInitialized = true;
return this.authenticationManager;
}
}
}
==//获取GlobalAuthenticationConfigurerAdapter配置对象,后面AuthenticationManager初始化会使用到==
@Autowired(required = false)
public void setGlobalAuthenticationConfigurers(List<GlobalAuthenticationConfigurerAdapter> configurers) throws Exception {
Collections.sort(configurers, AnnotationAwareOrderComparator.INSTANCE);
this.globalAuthConfigurers = configurers;
}
}
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#getHttp
protected final HttpSecurity getHttp() throws Exception {
if (this.http != null) {
return this.http;
} else {
DefaultAuthenticationEventPublisher eventPublisher = (DefaultAuthenticationEventPublisher)this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
//创建AuthenticationManager,就是上面讲的在WebSecurityConfigurerAdapter中被调用
AuthenticationManager authenticationManager = this.authenticationManager();
this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
Map<Class<? extends Object>, Object> sharedObjects = this.createSharedObjects();
this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
if (!this.disableDefaults) {
((HttpSecurity)((DefaultLoginPageConfigurer)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)this.http.csrf().and()).addFilter(new WebAsyncManagerIntegrationFilter()).exceptionHandling().and()).headers().and()).sessionManagement().and()).securityContext().and()).requestCache().and()).anonymous().and()).servletApi().and()).apply(new DefaultLoginPageConfigurer())).and()).logout();
ClassLoader classLoader = this.context.getClassLoader();
List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
Iterator var6 = defaultHttpConfigurers.iterator();
while(var6.hasNext()) {
AbstractHttpConfigurer configurer = (AbstractHttpConfigurer)var6.next();
this.http.apply(configurer);
}
}
this.configure(this.http);
return this.http;
}
}