Spring Security Config : AuthenticationConfiguration

Spring Security认证组件bean配置类。该配置类主要是定义或者搜集构建AuthenticationManager的构建器AuthenticationManagerBuilder所需要的一些bean,然后设置到AuthenticationManagerBuilder用于最终AuthenticationManager对象的构建。该配置类也会作为一个bean被注入到容器。它的典型用法如下 :

  1. 被注入到使用者;
  2. 使用者使用该bean获取AuthenticationManager : authenticationConfiguration.getAuthenticationManager()
    该方法的首次调用其实就会触发AuthenticationManagerBuilder构建目标对象AuthenticationManager

具体的使用例子可以参考WebSecurityConfigurerAdapter:

public abstract class WebSecurityConfigurerAdapter implements
		WebSecurityConfigurer<WebSecurity> {
	//...	

	// AuthenticationConfiguration authenticationConfiguration 是 
	// WebSecurityConfigurerAdapter 的一个依赖属性
	private AuthenticationConfiguration authenticationConfiguration;
	@Autowired
	public void setAuthenticationConfiguration(
			AuthenticationConfiguration authenticationConfiguration) {
		this.authenticationConfiguration = authenticationConfiguration;
	}
		
	//...
	
	// authenticationConfiguration 具体被使用的情况
	protected AuthenticationManager authenticationManager() throws Exception {
		if (!authenticationManagerInitialized) {
			configure(localConfigureAuthenticationBldr);
			if (disableLocalConfigureAuthenticationBldr) {
				authenticationManager = authenticationConfiguration
						.getAuthenticationManager();
			}
			else {
				authenticationManager = localConfigureAuthenticationBldr.build();
			}
			authenticationManagerInitialized = true;
		}
		return authenticationManager;
	}		
}		

源代码

源代码版本 : Spring Security Config 5.1.4.RELEASE

package org.springframework.security.config.annotation.authentication.configuration;

// 省略 imports

/**
 * Exports the authentication Configuration
 *
 * @author Rob Winch
 * @since 3.2
 *
 */
@Configuration
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {

    // 标志位,AuthenticationManager 是否正处于构建过程中
	private AtomicBoolean buildingAuthenticationManager = new AtomicBoolean();

	private ApplicationContext applicationContext;

	// 用于记录所要构建的 AuthenticationManager 
	private AuthenticationManager authenticationManager;

	// authenticationManagerInitialized 是 authenticationManager 是否已经被构建的标志,
	// 如果 authenticationManager 已经被构建,则 authenticationManagerInitialized 为 true,
	// 否则为 false
	private boolean authenticationManagerInitialized;

	private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigurers = Collections
			.emptyList();

	private ObjectPostProcessor<Object> objectPostProcessor;

	// 定义一个bean,认证管理器构建器  AuthenticationManagerBuilder, 该构建器最终被用于构建
	// AuthenticationManager 对象
	@Bean
	public AuthenticationManagerBuilder authenticationManagerBuilder(
			ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {
        // Lazy 密码加密器 : 该对象创建时容器中可能还不存在真正的密码加密器,
        // 但是用该 lazy密码加密器进行加密或者密码匹配时,会从容器中获取类型为 PasswordEncoder 的密码加密器,
        // 如果容器中不存在类型为 PasswordEncoder 的密码加密器,则使用  
        // PasswordEncoderFactories.createDelegatingPasswordEncoder() 创建一个 PasswordEncoder 
		// 供随后加密或者密码匹配使用
		// LazyPasswordEncoder 是定义在当前配置类中的一个内部类
		LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
		AuthenticationEventPublisher authenticationEventPublisher = 
			getBeanOrNull(context, AuthenticationEventPublisher.class);

        // 生成  AuthenticationManagerBuilder 实例,使用实现类为 DefaultPasswordEncoderAuthenticationManagerBuilder,
        // DefaultPasswordEncoderAuthenticationManagerBuilder 是定义在该配置类中的一个内部类, 它继承自 
        // AuthenticationManagerBuilder, 是 Spring Security 缺省使用的 AuthenticationManagerBuilder 实现类,
        // 它限定了密码加密器使用上面定义的 LazyPasswordEncoder defaultPasswordEncoder
		DefaultPasswordEncoderAuthenticationManagerBuilder result = 
			new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, defaultPasswordEncoder);
		if (authenticationEventPublisher != null) {
			result.authenticationEventPublisher(authenticationEventPublisher);
		}
		return result;
	}

    // 定义一个类型为 GlobalAuthenticationConfigurerAdapter  的 bean , 
    // 名称 : enableGlobalAuthenticationAutowiredConfigurer
    // 实现类型 : AuthenticationConfiguration$EnableGlobalAuthenticationAutowiredConfigurer 
    // 目的 : 1. 触发使用了注解@EnableGlobalAuthentication的bean的构建过程, 
    //         2. 如果是调试模式,则输出一条日志 : Eagerly initializing XXX
	@Bean
	public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(
			ApplicationContext context) {
		return new EnableGlobalAuthenticationAutowiredConfigurer(context);
	}

    // 定义一个类型为 GlobalAuthenticationConfigurerAdapter  的 bean , 
    // 名称 : initializeUserDetailsBeanManagerConfigurer
    // 实现类型 : InitializeUserDetailsBeanManagerConfigurer 
    // 目的 : 为 AuthenticationManagerBuilder 添加一个 InitializeUserDetailsManagerConfigurer 配置器,
    // InitializeUserDetailsManagerConfigurer 会在容器中没有用于构建 AuthenticationManager 的 
    // AuthenticationProvider bean,也没有为 AuthenticationManagerBuilder 设置 parent AuthenticationManager 时,
    // 尝试使用容器中类型为 UserDetailsService 的bean构造一个 DaoAuthenticationProvider 并设置到 
    // AuthenticationManagerBuilder 上, 当然,如果容器中连 UserDetailsService bean 也不存在,则
    // InitializeUserDetailsManagerConfigurer 什么都不做直接返回。
    // InitializeUserDetailsManagerConfigurer 构建 DaoAuthenticationProvider 时,如果容器中存在
    // PasswordEncoder , UserDetailsPasswordService 也会将它们应用到 DaoAuthenticationProvider 。
	@Bean
	public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(
			ApplicationContext context) {
		return new InitializeUserDetailsBeanManagerConfigurer(context);
	}

    // 定义一个类型为 GlobalAuthenticationConfigurerAdapter  的 bean , 
    // 名称 : initializeAuthenticationProviderBeanManagerConfigurer
    // 实现类型 : InitializeAuthenticationProviderBeanManagerConfigurer
    // 目的 : 为 AuthenticationManagerBuilder 设置 authenticationProvider, 所设置的
    // AuthenticationProvider 来自容器中类型为 AuthenticationProvider 的一个 bean,
    // 注意: 虽然 AuthenticationManagerBuilder 可以接受多个 AuthenticationProvider,
    // 但这里 InitializeAuthenticationProviderBeanManagerConfigurer 只会从容器中获得
    // 一个 AuthenticationProvider(如果有多个 AuthenticationProvider,则会返回 null,而不是采用第一个)。
	@Bean
	public static InitializeAuthenticationProviderBeanManagerConfigurer 
		initializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context) {
		return new InitializeAuthenticationProviderBeanManagerConfigurer(context);
	}

    // 根据配置生成认证管理器 AuthenticationManager
    // 1. 具备幂等性 2. 并且进行了同步处理 
    // 首次调用会触发真正的构建过程生成认证管理器 AuthenticationManager,
    // 再次的调用都会返回首次构建的认证管理器 AuthenticationManager
	public AuthenticationManager getAuthenticationManager() throws Exception {
        // authenticationManager 如果已经被构建则直接返回 authenticationManager
        // authenticationManagerInitialized 是 authenticationManager 是否已经被构建的标志位,
        // 如果 authenticationManager 已经被构建,则 authenticationManagerInitialized 为 true,
        // 否则为 false
		if (this.authenticationManagerInitialized) {
			return this.authenticationManager;
		}
        
        
       ///////////////////// 下面是  authenticationManager 构建过程 /////////////////////
       // 获取 authenticationManager 构建器 AuthenticationManagerBuilder authBuilder
		AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(
				this.objectPostProcessor, this.applicationContext);

        // 标志位 buildingAuthenticationManager 表示是否正在使用 authBuilder 进行构建
        // true 表示现在正在构建过程中, false 表示现在不在构建过程中
        // 下面的 getAndSet(true) 调用总是会
        // 1. 返回 buildingAuthenticationManager 之前的值
        // 2. 将 buildingAuthenticationManager 设置为 true
		if (this.buildingAuthenticationManager.getAndSet(true)) {
           // 如果已经正在使用 authBuilder 进行构建, 则这里直接返回一个包装了
           // 构建器 authBuilder 的 AuthenticationManagerDelegator 对象
			return new AuthenticationManagerDelegator(authBuilder);
		}

        // 在  authBuilder 上应用全局认证配置器, 
        // 这里所谓的"应用" 其实只是将 GlobalAuthenticationConfigurerAdapter 设置到
        // authBuilder,它们最终会在 authBuilder.build() 过程中会被真正使用
		for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
			authBuilder.apply(config);
		}

        // 构建器 authBuilder 执行构建,生成认证管理器 authenticationManager,
        // 具体的构建过程,可以参考 :
        // 1. AbstractSecurityBuilder#build
        // 2. AbstractConfiguredSecurityBuilder#doBuild
        // 这里 AbstractConfiguredSecurityBuilder 继承自 AbstractSecurityBuilder
		authenticationManager = authBuilder.build();

        //  如果容器中没有用于构建 AuthenticationManager 的 AuthenticationProvider bean
        //  供 authBuilder 使用,也没有为 authBuilder 设置 parent AuthenticationManager 时,
        //  则上面产生的 authenticationManager 为 null 。 不过这种情况缺省情况下并不会发生,
        //  因为该配置类中 bean InitializeUserDetailsBeanManagerConfigurer 为 authBuilder
        //  添加的 InitializeUserDetailsBeanManagerConfigurer 会在这种情况下构造一个 
        //  DaoAuthenticationProvider 对象给 authBuilder 使用。另外,一般情况下,开发人员也会
        // 提供自己的 AuthenticationProvider 实现类。 	              
       
        // 通常经过上面的 authBuilder.build(),authenticationManager 对象都会被创建,
        // 但是如果 authenticationManager 未被创建,这里尝试使用 getAuthenticationManagerBean()
        // 再次设置 authenticationManager
		if (authenticationManager == null) {
			// getAuthenticationManagerBean() 其实是返回一个实现了接口 AuthenticationManager
			// 的代理对象 , 通过 ProxyFactoryBean 对象工厂创建该代理对象
			authenticationManager = getAuthenticationManagerBean();
		}
       ///////////////////// 上面是  authenticationManager 构建过程 /////////////////////


        // authenticationManager 构建完成,将标志 authenticationManagerInitialized 设置为 true
		this.authenticationManagerInitialized = true;
		return authenticationManager;
	}

    // 可选设置全局认证配置器,这里指的全局认证配置器类型为 GlobalAuthenticationConfigurerAdapter,
    // 缺省为当前配置类定义的三个 GlobalAuthenticationConfigurerAdapter :
    // 实现类型分别为 : 
    // AuthenticationConfiguration$EnableGlobalAuthenticationAutowiredConfigurer 
    // InitializeAuthenticationProviderBeanManagerConfigurer
    // InitializeUserDetailsBeanManagerConfigurer
	@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;
	}

    // 创建实现了指定接口 interfaceName 的代理对象
	@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();
	}

    // 创建 AuthenticationManager 代理对象
	private AuthenticationManager getAuthenticationManagerBean() {
		return lazyBean(AuthenticationManager.class);
	}

    // 从容器中获取指定类型为 type 的bean,如果没找到则返回 null
	private static <T> T getBeanOrNull(ApplicationContext applicationContext, Class<T> type) {
		try {
			return applicationContext.getBean(type);
		} catch(NoSuchBeanDefinitionException notFound) {
			return null;
		}
	}

	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 + "]";
		}
	}

	static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder {
		private PasswordEncoder defaultPasswordEncoder;

		/**
		 * Creates a new instance
		 *
		 * @param objectPostProcessor the 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);
		}
	}

	static class LazyPasswordEncoder implements PasswordEncoder {
		private ApplicationContext applicationContext;
		private PasswordEncoder passwordEncoder;

		LazyPasswordEncoder(ApplicationContext applicationContext) {
			this.applicationContext = applicationContext;
		}

		@Override
		public String encode(CharSequence rawPassword) {
			return getPasswordEncoder().encode(rawPassword);
		}

		@Override
		public boolean matches(CharSequence rawPassword,
			String encodedPassword) {
			return getPasswordEncoder().matches(rawPassword, encodedPassword);
		}

		@Override
		public boolean upgradeEncoding(String encodedPassword) {
			return getPasswordEncoder().upgradeEncoding(encodedPassword);
		}

		private PasswordEncoder getPasswordEncoder() {
			if (this.passwordEncoder != null) {
				return this.passwordEncoder;
			}
			PasswordEncoder passwordEncoder = getBeanOrNull(this.applicationContext, PasswordEncoder.class);
			if (passwordEncoder == null) {
				passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
			}
			this.passwordEncoder = passwordEncoder;
			return passwordEncoder;
		}

		@Override
		public String toString() {
			return getPasswordEncoder().toString();
		}
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值