定制软件开发SpringSecurity------AuthenticationConfiguration配置类

SpringSecurity------AuthenticationConfiguration配置类

一、AuthenticationConfiguration定制软件开发是怎样被加载的

通过@EnableWebSecurity引入@EnableGlobalAuthentication注解,源码如下:

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,		HttpSecurityConfiguration.class })@EnableGlobalAuthentication@Configurationpublic @interface EnableWebSecurity {	/**	 * Controls debugging support for Spring Security. Default is false.	 * @return if true, enables debug support with Spring Security	 */	boolean debug() default false;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在@EnableGlobalAuthentication定制软件开发注解上使用@Import(AuthenticationConfiguration.class)定制软件开发注解引入本类

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(AuthenticationConfiguration.class)@Configurationpublic @interface EnableGlobalAuthentication {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

二、AuthenticationConfiguration定制软件开发主要做了什么

简单的说,定制软件开发这个类的作用就是用来创建ProviderManager,ProviderManager是一个AuthenticationManager实现,定制软件开发用于管理所有AuthenticationProvider定制软件开发实现的一个管理器。

首先,AuthenticationConfiguration类上的@Import()定制软件开发注解引入一个ObjectPostProcessorConfiguration类,该类会向ApplicationContext定制软件开发中添加一个ObjectPostProcessor的实现类,定制软件开发这个类提供spring定制软件开发的一些生命周期支持,定制软件开发被用于创建一些Bean。

然后,定制软件开发我们可以看到当前配置定制软件开发类上有两个关键属性authenticationManager和globalAuthConfigurers,其中authenticationManager用于存储一个AuthenticationManager对象,构建这个对象就是当前配置类的主要功能了;globalAuthConfigurers是存储全局配置的一个列表,三个默认的GlobalAuthenticationConfigurerAdapter实现会被注入到这个属性列表中,他们分别是:EnableGlobalAuthenticationAutowiredConfigurer(当前配置类的一个内部类)、InitializeAuthenticationProviderBeanManagerConfigurer、InitializeUserDetailsBeanManagerConfigurer,这三个类都是在当前配置类中使用@Bean注解引入,然后通过@Autowired注解的setGlobalAuthenticationConfigurers()方法将他们注入到globalAuthConfigurers属性中(源码分析中有具体介绍)。

接着,我们来看看创建AuthenticationManager的getAuthenticationManager()方法,他会从applicationContext中获取一个AuthenticationManagerBuilder,然后将全局配置globalAuthConfigurers中的配置设置到AuthenticationManagerBuilder中,然后使用这个AuthenticationManagerBuilder来创建一个AuthenticationManager对象。(具体的实现细节,下面的源码分析有介绍)。

那么,容器中的AuthenticationManagerBuilder是在那里初始化的呢?我们可以看到,在当前配置类中有一个带有@Bean注解的authenticationManagerBuilder()方法,这个方法创建一个DefaultPasswordEncoderAuthenticationManagerBuilder,他是AuthenticationManagerBuilder的一个实现类,这个类使用密码解码器的延时加载策略LazyPasswordEncoder,如果能从applicationContext中获取到AuthenticationEventPublisher,也会将这个事件发布器设置到AuthenticationManagerBuilder中。

总结,AuthenticationConfiguration会获取到容器中所有的GlobalAuthenticationConfigurerAdapter实现,然后创建一个默认的AuthenticationManagerBuilder(就是DefaultPasswordEncoderAuthenticationManagerBuilder),接着将所有GlobalAuthenticationConfigurerAdapter配置设置到DefaultPasswordEncoderAuthenticationManagerBuilder中,然后提供一个对外方法getAuthenticationManager(),这个方法中会获取到DefaultPasswordEncoderAuthenticationManagerBuilder,然后创建一个AuthenticationManager(就是ProviderManager),这就是AuthenticationConfiguration所做的事情。

三、AuthenticationConfiguration的源码分析

1、属性字段

//标志位,AuthenticationManager是否正处于构建过程中private AtomicBoolean buildingAuthenticationManager = new AtomicBoolean();//Application容器private ApplicationContext applicationContext;//用于记录所要构建的AuthenticationManager private AuthenticationManager authenticationManager;//AuthenticationManager是否已经被构建的标志private boolean authenticationManagerInitialized;//全局认证配置适配器列表private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigurers = Collections.emptyList();//对象后处理器private ObjectPostProcessor<Object> objectPostProcessor;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2、核心方法

内部构建AuthenticationManagerBuilder 的方法authenticationManagerBuilder()

构建一个AuthenticationManagerBuilder,用创建AuthenticationManager实例

@Beanpublic 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	 * 是SpringSecurity缺省使用的 AuthenticationManagerBuilder实现类	 */	DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(			objectPostProcessor, defaultPasswordEncoder);	/**	 *如果有事件发布器,则设置	 */	if (authenticationEventPublisher != null) {		result.authenticationEventPublisher(authenticationEventPublisher);	}	return result;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

对外构建AuthenticationManager方法getAuthenticationManager()

根据配置生成认证管理器 AuthenticationManager,该方法具有幂等性且进行了同步处理 。首次调用会触发真正的构建过程生成认证管理器 AuthenticationManager,再次的调用都会返回首次构建的认证管理器 AuthenticationManager。

public AuthenticationManager getAuthenticationManager() throws Exception {    //authenticationManager如果已经被构建则直接返回authenticationManager	if (this.authenticationManagerInitialized) {		return this.authenticationManager;	}	//获取容器中的AuthenticationManagerBuilder实例用于创建AuthenticationManager	AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);	// 如果已经正在使用authBuilder进行构建, 则这里直接返回一个包装了构建器authBuilder的AuthenticationManagerDelegator对象	// true表示现在正在构建过程中,false表示现在不在构建过程中	if (this.buildingAuthenticationManager.getAndSet(true)) {		return new AuthenticationManagerDelegator(authBuilder);	}	//将全局配置设置到AuthenticationManagerBuilder中	for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {		authBuilder.apply(config);	}	//构建AuthenticationManager	this.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 (this.authenticationManager == null) {		this.authenticationManager = getAuthenticationManagerBean();	}	//将authenticationManagerInitialized 设置为true,说明authenticationManager已经初始化完成	this.authenticationManagerInitialized = true;	//返回构建好的AuthenticationManager	return this.authenticationManager;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

3、使用@Bean初始化GlobalAuthenticationConfigurerAdapter的三个实现

定义一个EnableGlobalAuthenticationAutowiredConfigurer,他会加载使用了注解@EnableGlobalAuthentication的Bean,用于配置全局AuthenticationManagerBuilder:

@Beanpublic static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(		ApplicationContext context) {	//EnableGlobalAuthenticationAutowiredConfigurer是GlobalAuthenticationConfigurerAdapter的一个实现,当前配置类的内部类。	return new EnableGlobalAuthenticationAutowiredConfigurer(context);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

定义一个配置类,用于在没有配置单例的UserDetailsService时延时配置全局AuthenticationManagerBuilder:

@Beanpublic static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(		ApplicationContext context) {    //InitializeUserDetailsBeanManagerConfigurer是GlobalAuthenticationConfigurerAdapter的一个实现	return new InitializeUserDetailsBeanManagerConfigurer(context);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

定义一个配置类,用于在没有配置单例的UserDetailsService时延时加载全局AuthenticationProvider:

@Beanpublic static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(		ApplicationContext context) {	//InitializeAuthenticationProviderBeanManagerConfigurer是GlobalAuthenticationConfigurerAdapter的一个实现	return new InitializeAuthenticationProviderBeanManagerConfigurer(context);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4、使用@Autowired将一些Bean注入到当前配置类的属性中

注入GlobalAuthenticationConfigurerAdapter配置适配器,用于配置全局的AuthenticationManagerBuilder。三个默认的配置类会被注入到这里,他们分别是(这三个类都是在当前配置类中通过@Bean注解引入的):

  • EnableGlobalAuthenticationAutowiredConfigurer(当前配置类的一个内部类)
  • InitializeAuthenticationProviderBeanManagerConfigurer
  • InitializeUserDetailsBeanManagerConfigurer
@Autowired(required = false)public void setGlobalAuthenticationConfigurers(List<GlobalAuthenticationConfigurerAdapter> configurers) {	configurers.sort(AnnotationAwareOrderComparator.INSTANCE);	this.globalAuthConfigurers = configurers;}
  • 1
  • 2
  • 3
  • 4
  • 5

注入Application容器

@Autowiredpublic void setApplicationContext(ApplicationContext applicationContext) {	this.applicationContext = applicationContext;}
  • 1
  • 2
  • 3
  • 4

当前配置类上的@Import(ObjectPostProcessorConfiguration.class)引入的ObjectPostProcessorConfiguration会向容器中输出一个AutowireBeanFactoryObjectPostProcessor(ObjectPostProcessor的一个实现类)

@Autowiredpublic void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {	this.objectPostProcessor = objectPostProcessor;}	
  • 1
  • 2
  • 3
  • 4

5、当前类的私有方法、类注解、内部类

当前配置类的一些私有方法

private AuthenticationManager getAuthenticationManagerBean() {	return lazyBean(AuthenticationManager.class);}@SuppressWarnings("unchecked")private <T> T lazyBean(Class<T> interfaceName) {	LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();	String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.applicationContext,			interfaceName);	if (beanNamesForType.length == 0) {		return null;	}	String beanName = getBeanName(interfaceName, beanNamesForType);	lazyTargetSource.setTargetBeanName(beanName);	lazyTargetSource.setBeanFactory(this.applicationContext);	ProxyFactoryBean proxyFactory = new ProxyFactoryBean();	proxyFactory = this.objectPostProcessor.postProcess(proxyFactory);	proxyFactory.setTargetSource(lazyTargetSource);	return (T) proxyFactory.getObject();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
private <T> String getBeanName(Class<T> interfaceName, String[] beanNamesForType) {	if (beanNamesForType.length == 1) {		return beanNamesForType[0];	}	List<String> primaryBeanNames = getPrimaryBeanNames(beanNamesForType);	Assert.isTrue(primaryBeanNames.size() != 0, () -> "Found " + beanNamesForType.length + " beans for type "			+ interfaceName + ", but none marked as primary");	Assert.isTrue(primaryBeanNames.size() == 1,			() -> "Found " + primaryBeanNames.size() + " beans for type " + interfaceName + " marked as primary");	return primaryBeanNames.get(0);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
private List<String> getPrimaryBeanNames(String[] beanNamesForType) {	List<String> list = new ArrayList<>();	if (!(this.applicationContext instanceof ConfigurableApplicationContext)) {		return Collections.emptyList();	}	for (String beanName : beanNamesForType) {		if (((ConfigurableApplicationContext) this.applicationContext).getBeanFactory().getBeanDefinition(beanName)				.isPrimary()) {			list.add(beanName);		}	}	return list;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
private static <T> T getBeanOrNull(ApplicationContext applicationContext, Class<T> type) {	try {		return applicationContext.getBean(type);	} catch (NoSuchBeanDefinitionException notFound) {		return null;	}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

类注解@Import(ObjectPostProcessorConfiguration.class)

这个注解主要是引入ObjectPostProcessorConfiguration 类,该类向容器中注入一个实例

@Configuration(proxyBeanMethods = false)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public class ObjectPostProcessorConfiguration {	@Bean	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)	public ObjectPostProcessor<Object> objectPostProcessor(AutowireCapableBeanFactory beanFactory) {		return new AutowireBeanFactoryObjectPostProcessor(beanFactory);	}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

一些内部类

一个默认的GlobalAuthenticationConfigurerAdapter配置适配器实现,会在当前配置类中创建并注入到当前配置类的globalAuthConfigurers 属性中,主要作用是用来加载带有@EnableGlobalAuthentication注解的Bean, 如果是调试模式,还会输出一条日志 : Eagerly initializing XXX

private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter {	private final ApplicationContext context;	private static final Log logger = LogFactory.getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);	EnableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {		this.context = context;	}    //获取所有带有@EnableGlobalAuthentication注解的全局配置	@Override	public void init(AuthenticationManagerBuilder auth) {		Map<String, Object> beansWithAnnotation = this.context				.getBeansWithAnnotation(EnableGlobalAuthentication.class);		if (logger.isTraceEnabled()) {			logger.trace(LogMessage.format("Eagerly initializing %s", beansWithAnnotation));		}	}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

AuthenticationManagerDelegator 是AuthenticationManager的一个包装类或是委托类,主要是为了防止在初始化AuthenticationManager时发生无限递归:

  • 当这个内部类被构建时,会注入一个AuthenticationManagerBuilder实例。
  • authenticate()方法具有幂等性且进行了同步处理
    • 当这个类的authenticate()方法被第一次调用时会使用AuthenticationManagerBuilder创建一个AuthenticationManager保存到这个类的delegate属性中,同时将delegateBuilder置空,然后将实际鉴权处理交给AuthenticationManager。
    • 后续再调用authenticate()方法就只是使用已经创建好的AuthenticationManager实例
static final class AuthenticationManagerDelegator implements AuthenticationManager {	private AuthenticationManagerBuilder delegateBuilder;	private AuthenticationManager delegate;	private final Object delegateMonitor = new Object();    //初始化一个AuthenticationManagerBuilder实例	AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) {		Assert.notNull(delegateBuilder, "delegateBuilder cannot be null");		this.delegateBuilder = delegateBuilder;	}    //具有幂等性且进行了同步处理	@Override	public Authentication authenticate(Authentication authentication) throws AuthenticationException {	    //如果已经包含创建成功的AuthenticationManager,直接调用AuthenticationManager.authenticate()方法返回一个Authentication		if (this.delegate != null) {			return this.delegate.authenticate(authentication);		}		//如果没有包含创建成功的AuthenticationManager,进入同步方法		synchronized (this.delegateMonitor) {			if (this.delegate == null) {	    //使用AuthenticationManagerBuilder构建一个AuthenticationManager,	    //将值设置到AuthenticationManagerDelegator的delegate属性				this.delegate = this.delegateBuilder.getObject();				this.delegateBuilder = null;			}		}		//调用AuthenticationManager.authenticate()方法返回一个Authentication		return this.delegate.authenticate(authentication);	}	@Override	public String toString() {		return "AuthenticationManagerDelegator [delegate=" + this.delegate + "]";	}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder {	private PasswordEncoder defaultPasswordEncoder;	/**	 * Creates a new instance	 * 	 * @param objectPostProcessor the {@link 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);	}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发