首页 > 编程语言 >SpringSecurity源码-构建ProviderManager

SpringSecurity源码-构建ProviderManager

时间:2023-04-10 20:46:16浏览次数:41  
标签:AuthenticationManagerBuilder ProviderManager return auth SpringSecurity init 源码 

简介

在构建WenSecurity执行生命周期AbstractConfiguredSecurityBuilder#doBuild()方法中的init(),会执行到WebSecurityConfigurerAdapter#init(WebSecurity web) 方法,会去创建HttpSecurity。在创建HttpSecurity时调用authenticationManager()构建ProviderManager。
 

WebSecurityConfigurerAdapter#authenticationManager()

	protected AuthenticationManager authenticationManager() throws Exception {
	if (!this.authenticationManagerInitialized) {
		configure(this.localConfigureAuthenticationBldr);
		if (this.disableLocalConfigureAuthenticationBldr) {
			this.authenticationManager = this.authenticationConfiguration.getAuthenticationManager();
		}
		else {
			this.authenticationManager = this.localConfigureAuthenticationBldr.build();
		}
		this.authenticationManagerInitialized = true;
	}
	return this.authenticationManager;
}

默认调用authenticationConfiguration.getAuthenticationManager()构建AuthenticationManager,即ProviderManager。authenticationConfiguration是通过@Autowired自动注入的。

 

AuthenticationConfiguration来源

@EnableWebSecurity注解导入了@EnableGlobalAuthentication,看看@EnableGlobalAuthentication定义:

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

}

@EnableGlobalAuthentication导入了配置类AuthenticationConfiguration。这个AuthenticationConfiguration就是WebSecurityConfigurerAdapter中的AuthenticationConfiguration字段要注入的配置类。

 

看看AuthenticationConfiguration类中重要的方法:

@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
		ApplicationContext context) {
	LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
	AuthenticationEventPublisher authenticationEventPublisher = getAuthenticationEventPublisher(context);
	DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(
			objectPostProcessor, defaultPasswordEncoder);
	if (authenticationEventPublisher != null) {
		result.authenticationEventPublisher(authenticationEventPublisher);
	}
	return result;
}

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

创建了一个DefaultPasswordEncoderAuthenticationManagerBuilder bean和三个类型GlobalAuthenticationConfigurerAdapter的bean。

 

现在看看authenticationConfiguration.getAuthenticationManager():

	public AuthenticationManager getAuthenticationManager() throws Exception {
	if (this.authenticationManagerInitialized) {
		return this.authenticationManager;
	}
	AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
	if (this.buildingAuthenticationManager.getAndSet(true)) {
		return new AuthenticationManagerDelegator(authBuilder);
	}
	for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {
		authBuilder.apply(config);
	}
	this.authenticationManager = authBuilder.build();
	if (this.authenticationManager == null) {
		this.authenticationManager = getAuthenticationManagerBean();
	}
	this.authenticationManagerInitialized = true;
	return this.authenticationManager;
}

authBuilder就是上面的DefaultPasswordEncoderAuthenticationManagerBuilder。globalAuthConfigurers集合就是上面的EnableGlobalAuthenticationAutowiredConfigurer,InitializeUserDetailsBeanManagerConfigurer,InitializeAuthenticationProviderBeanManagerConfigurer。调用authBuilder.apply方法将EnableGlobalAuthenticationAutowiredConfigurer,InitializeUserDetailsBeanManagerConfigurer,InitializeAuthenticationProviderBeanManagerConfigurer加入到DefaultPasswordEncoderAuthenticationManagerBuilder的configurers属性中。
调用authBuilder.build()创建AuthenticationManager。

 

DefaultPasswordEncoderAuthenticationManagerBuilder类继承结构如下:

 

DefaultPasswordEncoderAuthenticationManagerBuilder继承了AbstractConfiguredSecurityBuilder。DefaultPasswordEncoderAuthenticationManagerBuilder#build()会调用到AbstractConfiguredSecurityBuilder#doBuild()执行生命周期构建。重点看init(),configure(),performBuild()。init()方法会调用configurers集合的中每个元素的init()方法。DefaultPasswordEncoderAuthenticationManagerBuilder中的configurers集合有EnableGlobalAuthenticationAutowiredConfigurer,InitializeUserDetailsBeanManagerConfigurer,InitializeAuthenticationProviderBeanManagerConfigurer。
 

DefaultPasswordEncoderAuthenticationManagerBuilder执行configurer类的init方法

EnableGlobalAuthenticationAutowiredConfigurer#init(AuthenticationManagerBuilder auth)

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

打印了日志。

 
先分别执行EnableGlobalAuthenticationAutowiredConfigurer,InitializeUserDetailsBeanManagerConfigurer,InitializeAuthenticationProviderBeanManagerConfigurer的init方法。

InitializeAuthenticationProviderBeanManagerConfigurer#init(AuthenticationManagerBuilder auth)

    @Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
	auth.apply(new InitializeAuthenticationProviderManagerConfigurer());
}

将InitializeAuthenticationProviderManagerConfigurer配置加入到DefaultPasswordEncoderAuthenticationManagerBuilder中的configurersAddedInInitializing属性和configurers属性。

 

InitializeUserDetailsBeanManagerConfigurer#init(AuthenticationManagerBuilder auth)

public void init(AuthenticationManagerBuilder auth) throws Exception {
	auth.apply(new InitializeUserDetailsManagerConfigurer());
}

将InitializeUserDetailsManagerConfigurer配置加入到DefaultPasswordEncoderAuthenticationManagerBuilder中的configurersAddedInInitializing属性和configurers属性。

 
执行完后DefaultPasswordEncoderAuthenticationManagerBuilder中的configurers集合有五个元素。执行完EnableGlobalAuthenticationAutowiredConfigurer,InitializeUserDetailsBeanManagerConfigurer,InitializeAuthenticationProviderBeanManagerConfigurer的init方法后又执行InitializeAuthenticationProviderManagerConfigurer,InitializeUserDetailsManagerConfigurer的init方法,这两个类的init方法是空方法,就不谈了。
 

DefaultPasswordEncoderAuthenticationManagerBuilder执行configurer类的configure方法

现在分别执行上面五个configurer的configure方法。三个类EnableGlobalAuthenticationAutowiredConfigurer,InitializeUserDetailsBeanManagerConfigurer,InitializeAuthenticationProviderBeanManagerConfigurer的configure是空方法就不谈了。

InitializeAuthenticationProviderManagerConfigurer#configure(AuthenticationManagerBuilder auth)

	@Override
	public void configure(AuthenticationManagerBuilder auth) {
		if (auth.isConfigured()) {
			return;
		}
		AuthenticationProvider authenticationProvider = getBeanOrNull(AuthenticationProvider.class);
		if (authenticationProvider == null) {
			return;
		}
		auth.authenticationProvider(authenticationProvider);
	}

默认AuthenticationProvider是null。
 

InitializeUserDetailsManagerConfigurer#configure(AuthenticationManagerBuilder auth)

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);
		UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);
		DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
		provider.setUserDetailsService(userDetailsService);
		if (passwordEncoder != null) {
			provider.setPasswordEncoder(passwordEncoder);
		}
		if (passwordManager != null) {
			provider.setUserDetailsPasswordService(passwordManager);
		}
		provider.afterPropertiesSet();
		auth.authenticationProvider(provider);
	}

创建了DaoAuthenticationProvider并添加到DefaultPasswordEncoderAuthenticationManagerBuilder的authenticationProviders字段中。

DefaultPasswordEncoderAuthenticationManagerBuilder执行performBuild方法

AuthenticationManagerBuilder#performBuild()

protected ProviderManager performBuild() throws Exception {
	if (!isConfigured()) {
		this.logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
		return null;
	}
	ProviderManager providerManager = new ProviderManager(this.authenticationProviders,
			this.parentAuthenticationManager);
	if (this.eraseCredentials != null) {
		providerManager.setEraseCredentialsAfterAuthentication(this.eraseCredentials);
	}
	if (this.eventPublisher != null) {
		providerManager.setAuthenticationEventPublisher(this.eventPublisher);
	}
	providerManager = postProcess(providerManager);
	return providerManager;
}

将authenticationProviders集合添加到ProviderManager中。authenticationProviders默认是DaoAuthenticationProvider。调用postProcess让ProviderManager执行Spring的Bean创建流程。

标签:AuthenticationManagerBuilder,ProviderManager,return,auth,SpringSecurity,init,源码,
From: https://www.cnblogs.com/shigongp/p/17304115.html

相关文章

  • vue2源码-二、对象响应式原理
    //循环对象进行一次劫持classObserver{constructor(value){this.walk()}walk(data){//重新定义属性Object.keys(data).forEach((key)=>defineReactive(data,key, data[key]))}}//属性劫持//对对象target,定义属性key,值为value//使用Object.definProperty重......
  • spring boot单库动态分表实现【增删查】(含源码)
    一.背景现实场景中当个别业务数据量过大时会影响系统功能性能,当整个业务还没有达到分库的级别时,动态分表也是一个的选择,基本思想是按照一定维度将数据分表存储动态查询。本次实现的是基于springboot的单表动态增删查,首先分表的规则根据一个格式生产,包含时间在其中,每一条数据......
  • C语言中的位运算符和源码反码补码的浅解
    位运算符【与(&);或(|);非(~);异或(^);移位运算符(<<和>>)】对于有符号(正负)的而言:1)二进制的最高位是符号位:0表示正数,1表示负数2)正数的原码,反码,补码都一样3)负数的反码=它的原码符号位不变,其它位取反(0->1,1->0)4)负数的补码=它的反码+1 5) 0在计算机种分+0与-0,它们的原码,补码,反码......
  • 直播网站源码,接收方收到的信息等于缓冲区长度
    直播网站源码,接收方收到的信息等于缓冲区长度原因分析:实际上是创建字符串时设置获取数据包的长度不正确,长度不应使用data.length byte[]data=packet.getData();Strings=newString(data,0,data.length);​解决方案:改用packet.getLength()即可解决 publicvoid......
  • Collection - LinkedList源码解析
    简介:LinkedList集合底层是一个双向链表结构,具有增删快,查询慢的特点,内部包含大量操作首尾元素的方法。适用于集合元素先入先出和先入后出的场景,在队列源码中被频繁使用。链表结构的节点新增、删除都非常简单,仅仅把前后节点的指向修改下就好了,所以LinkedList新增和删除速度很......
  • SpringSecurity之WebSecurity和HttpSecurity
    SpringSecurity启动过程中有两个重要的类。分别是WebSecurity和HttpSecurity。 看看WebSecurity的定义:publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware,Servl......
  • SpringSecurity源码之WebSecurity构建FilterChainProxy
    主要参考了https://mp.weixin.qq.com/s/D0weIKPto4lcuwl9DQpmvQ。SpringSecurity版本是2.7.9。将SpringBoot和SpringSecurity结合使用,SpringSecurity自动配置类是SecurityAutoConfiguration.class。 @AutoConfiguration@ConditionalOnClass({DefaultAuthenticationEventPubli......
  • 爬虫最后一天,爬取到的数据存到mysql中,爬虫和下载中间件、加代理、cookie、header、se
    爬到的数据存到mysql中classFirstscrapyMySqlPipeline:defopen_spider(self,spider):print('我开了')self.conn=pymysql.connect(user='root',password="",host='127.0.0.1......
  • SpringSecurity体系结构
    我是通过松哥的博客学习SpringSecurity的,地址是http://itboyhub.com/2021/01/26/spring-security-guide/。对SpringSecurity的使用有了初步的认识。并根据松哥的博客跟了源码,但是每个人的思路不一样,看完之后还有点模糊。对其中的一些用法不够深刻。想了下还是根据自己的思路记录下......
  • 【Spring专题】「技术原理」从源码角度去深入分析关于Spring的异常处理ExceptionHandl
    ExceptionHandler的作用ExceptionHandler是Spring框架提供的一个注解,用于处理应用程序中的异常。当应用程序中发生异常时,ExceptionHandler将优先地拦截异常并处理它,然后将处理结果返回到前端。该注解可用于类级别和方法级别,以捕获不同级别的异常。在Spring中使用ExceptionHandler非......