Spring Security中的DaoAuthenticationProvider

上一篇博客中已经了解了,认证的核心是各种AuthenticationProvider,这篇博客就来了解一下其中使用的最多的一个DaoAuthenticationProvider。

在此之前,先来了解一下三个类。UserDetails、UserDetailsService以及PasswordEncoder。

通俗的说,UserDetails是用户信息的实体类,UserDetailsService自定义实现,根据用户名密码加载UserDetails,PasswordEncoder就是密码的加密类。

看图,DaoAuthenticationProvider通过UserDetailsService以及PasswordEncoder,将用户名密码替换成UserDetails和Authorities。

接着看一看这个DaoAuthenticationProvider是从哪里配置来的,这个得从WebSecurityConfigurerAdapter说起。

在WebSecurityConfigurerAdapter中,以下代码之前都看过,AuthenticationManager 的由来也都说明过,其中有一个parent被所有的子AuthenticationManager共享,而这个DaoAuthenticationProvider就是包括在parent中。

protected final HttpSecurity getHttp() throws Exception {
		if (http != null) {
			return http;
		}

         //获取AuthenticationEventPublisher
		AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();
		localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);

        //配置parent的AuthenticationManager,可覆盖实现自定义方法
		AuthenticationManager authenticationManager = authenticationManager();
		authenticationBuilder.parentAuthenticationManager(authenticationManager);

		Map<Class<?>, Object> sharedObjects = createSharedObjects();

		//新建HttpSecurity,并构建一个默认的HttpSecurity
		http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
				sharedObjects);
		if (!disableDefaults) {
			// @formatter:off
			http
				.csrf().and()
				.addFilter(new WebAsyncManagerIntegrationFilter())
				.exceptionHandling().and()
				.headers().and()
				.sessionManagement().and()
				.securityContext().and()
				.requestCache().and()
				.anonymous().and()
				.servletApi().and()
				.apply(new DefaultLoginPageConfigurer<>()).and()
				.logout();
			// @formatter:on
			ClassLoader classLoader = this.context.getClassLoader();
			//spi 加载 AbstractHttpConfigurer的实现类,加入HttpSecurity中
			List<AbstractHttpConfigurer> defaultHttpConfigurers =
					SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
			for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
				http.apply(configurer);
			}
		}
		//配置HttpSecurity,可自定义实现
		configure(http);
		return http;
	}
	protected AuthenticationManager authenticationManager() throws Exception {
		//如果没有初始化过,执行方法
		if (!authenticationManagerInitialized) {

			//configure(AuthenticationManagerBuilder auth)
			//交给子类自定义
			configure(localConfigureAuthenticationBldr);

			//如果没有自定义过
			if (disableLocalConfigureAuthenticationBldr) {
				//使用默认的
				authenticationManager = authenticationConfiguration
						.getAuthenticationManager();
			}
			else {
				//否则使用自定义过的进行构建
				authenticationManager = localConfigureAuthenticationBldr.build();
			}
			authenticationManagerInitialized = true;
		}
		return authenticationManager;
	}

以上代码可以看出,这个parent如果不自定义的话,会使用默认的authenticationConfiguration,而这个如下是spring注入进来的

	@Autowired
	public void setAuthenticationConfiguration(
			AuthenticationConfiguration authenticationConfiguration) {
		this.authenticationConfiguration = authenticationConfiguration;
	}

接下来再看AuthenticationConfiguration 是怎么加到spring容器中的。

还是@EnableWebSecurity注解,注解了一个@EnableGlobalAuthentication,这个注解import了一个AuthenticationConfiguration。

//默认的情况获取AuthenticationManager
	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);
		}
         //放入三个configure,都在当前类中生成,GlobalAuthenticationConfigurerAdapter
		// InitializeUserDetailsBeanManagerConfigurer、InitializeAuthenticationProviderBeanManagerConfigurer
		for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
			authBuilder.apply(config);
		}

		authenticationManager = authBuilder.build();

		if (authenticationManager == null) {
			authenticationManager = getAuthenticationManagerBean();
		}

		this.authenticationManagerInitialized = true;
		return authenticationManager;
	}

 而在这个AuthenticationConfiguration中,会生成如上的AuthenticationManager,这个就是parent。

而在这个AuthenticationManager种,设置了多个globalAuthConfigurers

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

可以看到,当前类中有这么三个Configurer,其中InitializeUserDetailsBeanManagerConfigurer中会生成DaoAuthenticationProvider,要注意的是,这里并不是在这个类中直接生成的,而是如下,先注入了一个InitializeUserDetailsManagerConfigurer,在InitializeUserDetailsManagerConfigurer中创建的。

Configurer的逻辑前几篇博客已经说明过了

@Override
	public void init(AuthenticationManagerBuilder auth) throws Exception {
		auth.apply(new InitializeUserDetailsManagerConfigurer());
	}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
			if (auth.isConfigured()) {
				return;
			}
			//从spring中获取UserDetailsService,如果没有,直接返回
			//所以要执行下面的代码,必须要有UserDetailsService
			UserDetailsService userDetailsService = getBeanOrNull(
					UserDetailsService.class);
			if (userDetailsService == null) {
				return;
			}
           //从spring中获取PasswordEncoder
			PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
			
			UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);

			//构建DaoAuthenticationProvider
			DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
			provider.setUserDetailsService(userDetailsService);
			if (passwordEncoder != null) {
				provider.setPasswordEncoder(passwordEncoder);
			}
			if (passwordManager != null) {
				provider.setUserDetailsPasswordService(passwordManager);
			}
			provider.afterPropertiesSet();

           //将provider放入AuthenticationManagerBuilder中
			auth.authenticationProvider(provider);
		}

到此,DaoAuthenticationProvider的由来就已经清晰了。

再看看逻辑,如下代码,逻辑和之前描述一致。

	protected final UserDetails retrieveUser(String username,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
		prepareTimingAttackProtection();
		try {
			
			//调用UserDetailsService的loadUserByUsername方法,方法需要自定义
			UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
			if (loadedUser == null) {
				throw new InternalAuthenticationServiceException(
						"UserDetailsService returned null, which is an interface contract violation");
			}
			return loadedUser;
		}
		catch (UsernameNotFoundException ex) {
			mitigateAgainstTimingAttack(authentication);
			throw ex;
		}
		catch (InternalAuthenticationServiceException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
		}
	}

结束!

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security 是一个基于 Spring 框架的安全性框架,它提供了一系列的安全性服务和特性,例如身份验证、授权、攻击防护等。底层原理主要包括以下几个方面: 1. 核心架构 - Spring Security 的核心架构是基于 Filter Chain 的,它是一系列的 Filter 组成的链,每个 Filter 都处理一种特定的安全性问题,例如身份验证、授权等。 2. 安全性过滤器 - Spring Security 的安全性过滤器是 Filter Chain 的关键组件,它负责处理身份验证、授权等安全性相关的问题。Spring Security 提供了多种过滤器,例如 UsernamePasswordAuthenticationFilter 用于处理用户名密码身份验证,BasicAuthenticationFilter 用于处理基本身份验证等。 3. Spring Security 上下文 - Spring Security 上下文是一个 SecurityContext 对象,它包含了当前访问用户的身份验证和授权信息,例如用户名、密码、角色等。Spring Security 使用 ThreadLocal 存储上下文信息,并通过 SecurityContextHolder 对象提供了一系列的访问方法。 4. 认证管理器 - 认证管理器是 Spring Security 的核心组件,它负责处理身份验证的全部逻辑。Spring Security 提供了多种认证管理器,例如 ProviderManager 用于处理多个身份验证器的情况,DaoAuthenticationProvider 用于处理数据库身份验证等。 5. 安全性注解 - Spring Security 还提供了多种安全性注解,例如 @Secured、@PreAuthorize、@PostAuthorize 等,它们可以用于控制方法的访问权限,实现基于注解的访问控制。 总之,Spring Security 是一个功能强大、灵活、易扩展的安全性框架,它提供了多种安全性特性和服务,可以帮助开发人员轻松实现安全性功能,保障应用程序的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值