SpringSecurity------AuthenticationConfiguration配置类

一、AuthenticationConfiguration是怎样被加载的

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
		HttpSecurityConfiguration.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;

}

在@EnableGlobalAuthentication注解上使用@Import(AuthenticationConfiguration.class)注解引入本类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {

}

二、AuthenticationConfiguration主要做了什么

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

首先,AuthenticationConfiguration类上的@Import()注解引入一个ObjectPostProcessorConfiguration类,该类会向ApplicationContext中添加一个ObjectPostProcessor的实现类AutowireBeanFactoryObjectPostProcessor,这个类提供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;

2、核心方法

内部构建AuthenticationManagerBuilder 的方法authenticationManagerBuilder()

构建一个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
	 * 是SpringSecurity缺省使用的 AuthenticationManagerBuilder实现类
	 */
	DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(
			objectPostProcessor, defaultPasswordEncoder);
	/**
	 *如果有事件发布器,则设置
	 */
	if (authenticationEventPublisher != null) {
		result.authenticationEventPublisher(authenticationEventPublisher);
	}
	return result;
}

对外构建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;
}

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

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

@Bean
public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(
		ApplicationContext context) {
	//EnableGlobalAuthenticationAutowiredConfigurer是GlobalAuthenticationConfigurerAdapter的一个实现,当前配置类的内部类。
	return new EnableGlobalAuthenticationAutowiredConfigurer(context);
}

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

@Bean
public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(
		ApplicationContext context) {
    //InitializeUserDetailsBeanManagerConfigurer是GlobalAuthenticationConfigurerAdapter的一个实现
	return new InitializeUserDetailsBeanManagerConfigurer(context);
}

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

@Bean
public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(
		ApplicationContext context) {
	//InitializeAuthenticationProviderBeanManagerConfigurer是GlobalAuthenticationConfigurerAdapter的一个实现
	return new InitializeAuthenticationProviderBeanManagerConfigurer(context);
}

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;
}

注入Application容器

@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
	this.applicationContext = applicationContext;
}

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

@Autowired
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
	this.objectPostProcessor = objectPostProcessor;
}	

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();
}
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);
}
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;
}
private static <T> T getBeanOrNull(ApplicationContext applicationContext, Class<T> type) {
	try {
		return applicationContext.getBean(type);
	} catch (NoSuchBeanDefinitionException notFound) {
		return null;
	}
}

类注解@Import(ObjectPostProcessorConfiguration.class)

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

@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);
	}
}

一些内部类

一个默认的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));
		}
	}
}

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 + "]";
	}
}
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);
	}
}
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();
	}
}
Spring Authorization Server 是 Spring 官方提供的一个 OAuth2 与 OpenID Connect 认证服务的实现,它可以用于构建安全的 RESTful API 或 Web 应用。 在 Spring Authorization Server 中,自定义认证配置的方式与 Spring Security似,主要有以下几个步骤: 1. 创建一个实现了 `org.springframework.security.config.annotation.authentication.configurers.provisioning.UserDetailsManagerConfigurer` 接口的配置,并在其中配置自定义的用户信息。 2. 在 `AuthorizationServerSecurityConfigurer` 中配置认证端点的安全性,包括认证方式、允许访问的角色等。 3. 在 `AuthorizationServerEndpointsConfigurer` 中配置认证服务的端点,包括认证端点、令牌端点、用户信息端点等。 例如,下面是一个简单的自定义认证配置示例: ```java @Configuration public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.checkTokenAccess("isAuthenticated()"); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client") .secret("{noop}secret") .authorizedGrantTypes("password", "refresh_token") .scopes("read", "write") .accessTokenValiditySeconds(3600) .refreshTokenValiditySeconds(86400); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager); } @Configuration @Order(Ordered.HIGHEST_PRECEDENCE) protected static class AuthenticationManagerConfiguration extends GlobalAuthenticationConfigurerAdapter { @Override public void init(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user") .password("{noop}password") .roles("USER"); } } } ``` 在上面的示例中,`AuthorizationServerConfig` 是自定义认证配置的入口点,其中: - `configure(AuthorizationServerSecurityConfigurer security)` 方法配置了认证端点的安全性,这里设置了访问令牌需要经过身份验证。 - `configure(ClientDetailsServiceConfigurer clients)` 方法配置了客户端信息,这里使用了一个内存中的客户端信息服务。 - `configure(AuthorizationServerEndpointsConfigurer endpoints)` 方法配置了认证服务的端点,这里使用了一个 `AuthenticationManager` 来处理身份验证请求。 - `AuthenticationManagerConfiguration` 是一个内部配置,用于配置自定义的用户信息。 需要注意的是,以上示例中使用了一个内存中的用户信息服务和客户端信息服务,实际应用中可以替换为数据库或其他持久化存储方式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豢龙先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值