当前位置: 代码迷 >> 综合 >> SpringSecurity------AuthenticationConfiguration配置类
  详细解决方案

SpringSecurity------AuthenticationConfiguration配置类

热度:22   发布时间:2023-12-20 23:13:26.0

SpringSecurity------AuthenticationConfiguration配置类

  • 一、AuthenticationConfiguration是怎样被加载的
  • 二、AuthenticationConfiguration主要做了什么
  • 三、AuthenticationConfiguration的源码分析
    • 1、属性字段
    • 2、核心方法
      • 内部构建AuthenticationManagerBuilder 的方法authenticationManagerBuilder()
      • 对外构建AuthenticationManager方法getAuthenticationManager()
    • 3、使用@Bean初始化GlobalAuthenticationConfigurerAdapter的三个实现
    • 4、使用@Autowired将一些Bean注入到当前配置类的属性中
    • 5、当前类的私有方法、类注解、内部类
      • 当前配置类的一些私有方法
      • 类注解@Import(ObjectPostProcessorConfiguration.class)
      • 一些内部类

一、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如果已经被构建则直接返回authenticationManagerif (this.authenticationManagerInitialized) {
    return this.authenticationManager;}//获取容器中的AuthenticationManagerBuilder实例用于创建AuthenticationManagerAuthenticationManagerBuilder 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);}//构建AuthenticationManagerthis.authenticationManager = authBuilder.build();// 如果容器中没有用于构建 AuthenticationManager 的 AuthenticationProvider bean// 供 authBuilder 使用,也没有为 authBuilder 设置 parent AuthenticationManager 时,// 则上面产生的 authenticationManager 为 null 。 不过这种情况缺省情况下并不会发生,// 因为该配置类中 bean InitializeUserDetailsBeanManagerConfigurer 为 authBuilder// 添加的 InitializeUserDetailsBeanManagerConfigurer 会在这种情况下构造一个 // DaoAuthenticationProvider 对象给 authBuilder 使用。另外,一般情况下,开发人员也会// 提供自己的 AuthenticationProvider 实现类。 // 通常经过上面的 authBuilder.build(),authenticationManager 对象都会被创建,// 但是如果 authenticationManager 未被创建,这里尝试使用 getAuthenticationManagerBean()// 再次设置 authenticationManagerif (this.authenticationManager == null) {
    this.authenticationManager = getAuthenticationManagerBean();}//将authenticationManagerInitialized 设置为true,说明authenticationManager已经初始化完成this.authenticationManagerInitialized = true;//返回构建好的AuthenticationManagerreturn 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注解的全局配置@Overridepublic 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;}//具有幂等性且进行了同步处理@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {
    //如果已经包含创建成功的AuthenticationManager,直接调用AuthenticationManager.authenticate()方法返回一个Authenticationif (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()方法返回一个Authenticationreturn this.delegate.authenticate(authentication);}@Overridepublic 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;}@Overridepublic InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()throws Exception {
    return super.inMemoryAuthentication().passwordEncoder(this.defaultPasswordEncoder);}@Overridepublic JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
    return super.jdbcAuthentication().passwordEncoder(this.defaultPasswordEncoder);}@Overridepublic <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;}@Overridepublic String encode(CharSequence rawPassword) {
    return getPasswordEncoder().encode(rawPassword);}@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {
    return getPasswordEncoder().matches(rawPassword, encodedPassword);}@Overridepublic 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;}@Overridepublic String toString() {
    return getPasswordEncoder().toString();}
}
  相关解决方案