在上上篇spring security 源碼學習(三)WebSecurityConfiguration中對AuthenticationManager做過簡單的介紹,這里,我們詳細分析下AuthenticationManager。
先簡單描述下標題的這3個類有啥關系,AuthenticationManager是Spring Security用來認證的,ProviderManager是AuthenticationManager的一個實現,而AuthenticationConfiguration則是誕生(初始化)AuthenticationManager的配置類。
AuthenticationManager的初始化是在HttpSecurity初始化時,順帶初始化的。。。開玩笑,AuthenticationManager也是非常重要的。讓我們再回顧下
protected final HttpSecurity getHttp() throws Exception { if (http != null) { return http; } DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor .postProcess(new DefaultAuthenticationEventPublisher()); localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher); AuthenticationManager authenticationManager = authenticationManager(); authenticationBuilder.parentAuthenticationManager(authenticationManager); Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects(); 。。。。。。 }
authenticationManager()方法如下:
protected AuthenticationManager authenticationManager() throws Exception { //看是否初始化過,如果初始化過,不再初始化 if (!authenticationManagerInitialized) { //提供自定義的地方,這邊按照我們沒加自定義那么執行的是 this.disableLocalConfigureAuthenticationBldr = true; configure(localConfigureAuthenticationBldr); if (disableLocalConfigureAuthenticationBldr) { authenticationManager = authenticationConfiguration .getAuthenticationManager(); } else { authenticationManager = localConfigureAuthenticationBldr.build(); } authenticationManagerInitialized = true; } return authenticationManager; }
根據上面的注釋,可以看到初始化就在authenticationConfiguration.getAuthenticationManager();讓我們來看下這段代碼:
public AuthenticationManager getAuthenticationManager() throws Exception { if (this.authenticationManagerInitialized) { return this.authenticationManager; } //執行了new AuthenticationManagerBuilder(objectPostProcessor); AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder( this.objectPostProcessor); //如果是第一次,那么這里就會把值改為true,表示正在構建AuthenticationManager,不會進入到if體里去 //如果正在構建時又來到這,則會返回一個包裝了AuthenticationManagerBuilder的AuthenticationManager的代理類AuthenticationManagerDelegator if (this.buildingAuthenticationManager.getAndSet(true)) { return new AuthenticationManagerDelegator(authBuilder); } //這里就是在上一次未講的地方,這里出現了5個配置類 for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) { //老樣子,將配置類加入到AuthenticationManagerBuilder的父類AbstractConfiguredSecurityBuilder的 //LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers屬性中,待build authBuilder.apply(config); } //老規矩,老的build那套 authenticationManager = authBuilder.build(); if (authenticationManager == null) { authenticationManager = getAuthenticationManagerBean(); } this.authenticationManagerInitialized = true; return authenticationManager; }
GlobalAuthenticationConfigurerAdapter在spring中的幾個實例是哪來的呢?
一部分是從這里來的AuthenticationConfiguration,而AuthenticationConfiguration則是被EnableGlobalAuthentication引入的,EnableGlobalAuthentication則是在EnableWebSecurity時引入的,這么說有點抽象,來幾個代碼就清楚了
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) @Target(value = { java.lang.annotation.ElementType.TYPE }) @Documented @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.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; }
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) @Target(value = { java.lang.annotation.ElementType.TYPE }) @Documented @Import(AuthenticationConfiguration.class) @Configuration public @interface EnableGlobalAuthentication { }
@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; @Bean public AuthenticationManagerBuilder authenticationManagerBuilder( ObjectPostProcessor<Object> objectPostProcessor) { return new AuthenticationManagerBuilder(objectPostProcessor); } @Bean public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer( ApplicationContext context) { return new EnableGlobalAuthenticationAutowiredConfigurer(context); } @Bean public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) { return new InitializeUserDetailsBeanManagerConfigurer(context); } @Bean public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context) { return new InitializeAuthenticationProviderBeanManagerConfigurer(context); } public AuthenticationManager getAuthenticationManager() throws Exception { if (this.authenticationManagerInitialized) { return this.authenticationManager; } AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder( this.objectPostProcessor); if (this.buildingAuthenticationManager.getAndSet(true)) { return new AuthenticationManagerDelegator(authBuilder); } for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) { authBuilder.apply(config); } authenticationManager = authBuilder.build(); if (authenticationManager == null) { authenticationManager = getAuthenticationManagerBean(); } this.authenticationManagerInitialized = true; return authenticationManager; } @Autowired(required = false) public void setGlobalAuthenticationConfigurers( List<GlobalAuthenticationConfigurerAdapter> configurers) throws Exception { Collections.sort(configurers, AnnotationAwareOrderComparator.INSTANCE); this.globalAuthConfigurers = configurers; } @Autowired public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } @Autowired public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) { this.objectPostProcessor = objectPostProcessor; } @SuppressWarnings("unchecked") private <T> T lazyBean(Class<T> interfaceName) { LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource(); String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( applicationContext, interfaceName); if (beanNamesForType.length == 0) { return null; } Assert.isTrue(beanNamesForType.length == 1, "Expecting to only find a single bean for type " + interfaceName + ", but found " + Arrays.asList(beanNamesForType)); lazyTargetSource.setTargetBeanName(beanNamesForType[0]); lazyTargetSource.setBeanFactory(applicationContext); ProxyFactoryBean proxyFactory = new ProxyFactoryBean(); proxyFactory = objectPostProcessor.postProcess(proxyFactory); proxyFactory.setTargetSource(lazyTargetSource); return (T) proxyFactory.getObject(); } private AuthenticationManager getAuthenticationManagerBean() { return lazyBean(AuthenticationManager.class); } private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter { private final ApplicationContext context; private static final Log logger = LogFactory .getLog(EnableGlobalAuthenticationAutowiredConfigurer.class); public EnableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) { this.context = context; } @Override public void init(AuthenticationManagerBuilder auth) { Map<String, Object> beansWithAnnotation = context .getBeansWithAnnotation(EnableGlobalAuthentication.class); if (logger.isDebugEnabled()) { logger.debug("Eagerly initializing " + beansWithAnnotation); } } } /** * Prevents infinite recursion in the event that initializing the * AuthenticationManager. * * @author Rob Winch * @since 4.1.1 */ static final class AuthenticationManagerDelegator implements AuthenticationManager { private AuthenticationManagerBuilder delegateBuilder; private AuthenticationManager delegate; private final Object delegateMonitor = new Object(); AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) { Assert.notNull(delegateBuilder, "delegateBuilder cannot be null"); this.delegateBuilder = delegateBuilder; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { if (this.delegate != null) { return this.delegate.authenticate(authentication); } synchronized (this.delegateMonitor) { if (this.delegate == null) { this.delegate = this.delegateBuilder.getObject(); this.delegateBuilder = null; } } return this.delegate.authenticate(authentication); } @Override public String toString() { return "AuthenticationManagerDelegator [delegate=" + this.delegate + "]"; } } }
由上面的一連串代碼,可以看到有3個GlobalAuthenticationConfigurerAdapter的子類,EnableGlobalAuthenticationAutowiredConfigurer、InitializeUserDetailsBeanManagerConfigurer、InitializeAuthenticationProviderBeanManagerConfigurer被加入到了AuthenticationConfiguration中,待用來初始化,那么還有2個是哪來的
EnableGlobalAuthenticationAutowiredConfigurer
private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter { private final ApplicationContext context; private static final Log logger = LogFactory .getLog(EnableGlobalAuthenticationAutowiredConfigurer.class); public EnableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) { this.context = context; } @Override public void init(AuthenticationManagerBuilder auth) { Map<String, Object> beansWithAnnotation = context .getBeansWithAnnotation(EnableGlobalAuthentication.class); if (logger.isDebugEnabled()) { logger.debug("Eagerly initializing " + beansWithAnnotation); } } }
從源碼中可以看出,這個類其實沒干啥,就是會觸發下注解了@EnableGlobalAuthentication的bean的初始化。
InitializeUserDetailsBeanManagerConfigurer
@Order(InitializeUserDetailsBeanManagerConfigurer.DEFAULT_ORDER) class InitializeUserDetailsBeanManagerConfigurer extends GlobalAuthenticationConfigurerAdapter { static final int DEFAULT_ORDER = Ordered.LOWEST_PRECEDENCE - 5000; private final ApplicationContext context; /** * @param context */ public InitializeUserDetailsBeanManagerConfigurer(ApplicationContext context) { this.context = context; } @Override public void init(AuthenticationManagerBuilder auth) throws Exception { auth.apply(new InitializeUserDetailsManagerConfigurer()); } class InitializeUserDetailsManagerConfigurer extends GlobalAuthenticationConfigurerAdapter { @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { if (auth.isConfigured()) { return; } UserDetailsService userDetailsService = getBeanOrNull( UserDetailsService.class); if (userDetailsService == null) { return; } PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setUserDetailsService(userDetailsService); if (passwordEncoder != null) { provider.setPasswordEncoder(passwordEncoder); } //將上面new的DaoAuthenticationProvider加入到AuthenticationManagerBuilder的List<AuthenticationProvider> authenticationProviders中。 auth.authenticationProvider(provider); } /** * @return */ private <T> T getBeanOrNull(Class<T> type) { String[] userDetailsBeanNames = InitializeUserDetailsBeanManagerConfigurer.this.context .getBeanNamesForType(type); if (userDetailsBeanNames.length != 1) { return null; } return InitializeUserDetailsBeanManagerConfigurer.this.context .getBean(userDetailsBeanNames[0], type); } } }
從源碼中可以看出來,這個類的init是將InitializeUserDetailsManagerConfigurer加入了AuthenticationManagerBuilder用於configure,而InitializeUserDetailsManagerConfigurer的configure則是從容器中獲取UserDetailsService和PasswordEncoder的實現類,如果UserDetailsService沒有實現類,則直接返回,有的話則new一個DaoAuthenticationProvider加入到AuthenticationManagerBuilder的List<AuthenticationProvider> authenticationProviders中。
InitializeAuthenticationProviderBeanManagerConfigurer
@Order(InitializeAuthenticationProviderBeanManagerConfigurer.DEFAULT_ORDER) class InitializeAuthenticationProviderBeanManagerConfigurer extends GlobalAuthenticationConfigurerAdapter { static final int DEFAULT_ORDER = InitializeUserDetailsBeanManagerConfigurer.DEFAULT_ORDER - 100; private final ApplicationContext context; /** * @param context the ApplicationContext to look up beans. */ public InitializeAuthenticationProviderBeanManagerConfigurer( ApplicationContext context) { this.context = context; } @Override public void init(AuthenticationManagerBuilder auth) throws Exception { auth.apply(new InitializeUserDetailsManagerConfigurer()); } class InitializeUserDetailsManagerConfigurer extends GlobalAuthenticationConfigurerAdapter { @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { if (auth.isConfigured()) { return; } AuthenticationProvider authenticationProvider = getBeanOrNull( AuthenticationProvider.class); if (authenticationProvider == null) { return; } auth.authenticationProvider(authenticationProvider); } /** * @return */ private <T> T getBeanOrNull(Class<T> type) { String[] userDetailsBeanNames = InitializeAuthenticationProviderBeanManagerConfigurer.this.context .getBeanNamesForType(type); if (userDetailsBeanNames.length != 1) { return null; } return InitializeAuthenticationProviderBeanManagerConfigurer.this.context .getBean(userDetailsBeanNames[0], type); } } }
從源碼中可以看出,從Spring的容器中獲取AuthenticationProvider的實現類,加入到uthenticationManagerBuilder的List<AuthenticationProvider> authenticationProviders中。
ps:注意InitializeUserDetailsBeanManagerConfigurer、InitializeAuthenticationProviderBeanManagerConfigurer這兩個類都是懶加載,目的就是將容器中的所有AuthenticationProvider的實現類加入到uthenticationManagerBuilder的List<AuthenticationProvider> authenticationProviders中。