在上上篇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中。