栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Security:身份验证提供程序AuthenticationProvider介绍

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Security:身份验证提供程序AuthenticationProvider介绍

AuthenticationProvider

AuthenticationProvider可以处理特定的Authentication实现。

Spring Security:身份验证令牌Authentication介绍与Debug分析

Authentication接口及其实现类如下图所示:

AuthenticationProvider接口及其实现类如下图所示:

public interface AuthenticationProvider {

	
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;

	
	boolean supports(Class authentication);
}
TestingAuthenticationProvider

验证TestingAuthenticationToken的AuthenticationProvider实现,此实现的目的是用于单元测试,不应在生产环境中使用它。

public class TestingAuthenticationProvider implements AuthenticationProvider {
    // 直接返回authentication实例,用于单元测试
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		return authentication;
	}
    
    // 支持TestingAuthenticationToken类型的身份验证请求令牌
	public boolean supports(Class authentication) {
		return TestingAuthenticationToken.class.isAssignableFrom(authentication);
	}
}
AnonymousAuthenticationProvider

验证AnonymousAuthenticationToken的AuthenticationProvider实现。要成功验证,AnonymousAuthenticationToken.getKeyHash()必须与此类的getKey()匹配。

public class AnonymousAuthenticationProvider implements AuthenticationProvider,
		MessageSourceAware {
	// 用于访问来自MessageSource的消息
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	// 识别Authentication实例是否由授权客户生成的key
	private String key;

    // 使用key构造AnonymousAuthenticationProvider实例
	public AnonymousAuthenticationProvider(String key) {
		Assert.hasLength(key, "A Key is required");
		this.key = key;
	}

    // 进行验证
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		// 是否支持该Authentication实例
		if (!supports(authentication.getClass())) {
			return null;
		}
       
        // AnonymousAuthenticationToken.getKeyHash()必须与此类的getKey()匹配才能验证成功
		if (this.key.hashCode() != ((AnonymousAuthenticationToken) authentication)
				.getKeyHash()) {
			throw new BadCredentialsException(
					messages.getMessage("AnonymousAuthenticationProvider.incorrectKey",
							"The presented AnonymousAuthenticationToken does not contain the expected key"));
		}

		return authentication;
	}
	 
	// 返回key属性
	public String getKey() {
		return key;
	}

    // 设置messages属性
	public void setMessageSource(MessageSource messageSource) {
		Assert.notNull(messageSource, "messageSource cannot be null");
		this.messages = new MessageSourceAccessor(messageSource);
	}
    
    // 支持AnonymousAuthenticationToken类型
	public boolean supports(Class authentication) {
		return (AnonymousAuthenticationToken.class.isAssignableFrom(authentication));
	}
}
RememberMeAuthenticationProvider

验证RememberMeAuthenticationToken的AuthenticationProvider实现。要成功验证, RememberMeAuthenticationToken.getKeyHash()必须与此类的getKey()匹配。

public class RememberMeAuthenticationProvider implements AuthenticationProvider,
		InitializingBean, MessageSourceAware {
    // 用于访问来自MessageSource的消息
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	// 识别Authentication实例是否由授权客户生成的key
	private String key;

    // 使用key构造AnonymousAuthenticationProvider实例
	public RememberMeAuthenticationProvider(String key) {
		Assert.hasLength(key, "key must have a length");
		this.key = key;
	}

    // 检查messages属性是否为null
	public void afterPropertiesSet() {
		Assert.notNull(this.messages, "A message source must be set");
	}

    // 进行验证
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		// 是否支持该Authentication实例
		if (!supports(authentication.getClass())) {
			return null;
		}
      
        // RememberMeAuthenticationToken.getKeyHash()必须与此类的getKey()匹配才能验证成功
		if (this.key.hashCode() != ((RememberMeAuthenticationToken) authentication)
				.getKeyHash()) {
			throw new BadCredentialsException(
					messages.getMessage("RememberMeAuthenticationProvider.incorrectKey",
							"The presented RememberMeAuthenticationToken does not contain the expected key"));
		}

		return authentication;
	}

    // 返回key属性
	public String getKey() {
		return key;
	}

    // 设置messages属性
	public void setMessageSource(MessageSource messageSource) {
		this.messages = new MessageSourceAccessor(messageSource);
	}

    // 支持RememberMeAuthenticationToken类型
	public boolean supports(Class authentication) {
		return (RememberMeAuthenticationToken.class.isAssignableFrom(authentication));
	}
}
RemoteAuthenticationProvider

使用RemoteAuthenticationManager验证身份验证请求的客户端对象。此类创建一个新的Authentication对象,包括请求Authentication对象的principal 、 credentials和RemoteAuthenticationManager返回的GrantedAuthority集合。

public class RemoteAuthenticationProvider implements AuthenticationProvider,
		InitializingBean {
    
    // RemoteAuthenticationManager用于允许远程客户端尝试身份验证
	private RemoteAuthenticationManager remoteAuthenticationManager;

	// 检查remoteAuthenticationManager属性是否为null
	public void afterPropertiesSet() {
		Assert.notNull(this.remoteAuthenticationManager,
				"remoteAuthenticationManager is mandatory");
	}

    // 进行验证
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		// 获取用户名
		String username = authentication.getPrincipal().toString();
		// 获取凭据
		Object credentials = authentication.getCredentials();
		// 根据凭据获取密码
		String password = credentials == null ? null : credentials.toString();
		// 将RemoteAuthenticationManager处理验证请求的结果作为权限集合
		Collection authorities = remoteAuthenticationManager
				.attemptAuthentication(username, password);

        // 返回UsernamePasswordAuthenticationToken实例
		return new UsernamePasswordAuthenticationToken(username, password, authorities);
	}

    // 返回remoteAuthenticationManager 属性
	public RemoteAuthenticationManager getRemoteAuthenticationManager() {
		return remoteAuthenticationManager;
	}

    // 设置remoteAuthenticationManager 属性
	public void setRemoteAuthenticationManager(
			RemoteAuthenticationManager remoteAuthenticationManager) {
		this.remoteAuthenticationManager = remoteAuthenticationManager;
	}

    // 支持UsernamePasswordAuthenticationToken类型
	public boolean supports(Class authentication) {
		return (UsernamePasswordAuthenticationToken.class
				.isAssignableFrom(authentication));
	}
}
RemoteAuthenticationManager

允许远程客户端尝试身份验证。

public interface RemoteAuthenticationManager {
	
	Collection attemptAuthentication(String username,
			String password) throws RemoteAuthenticationException;
}
RemoteAuthenticationManagerImpl

RemoteAuthenticationManager接口的实现类。

public class RemoteAuthenticationManagerImpl implements RemoteAuthenticationManager,
		InitializingBean {
	// AuthenticationManager实例,用于处理身份验证请求
	private AuthenticationManager authenticationManager;

	// 检查authenticationManager属性是否为null
	public void afterPropertiesSet() {
		Assert.notNull(this.authenticationManager, "authenticationManager is required");
	}

    // 尝试验证
	public Collection attemptAuthentication(String username,
			String password) throws RemoteAuthenticationException {
		// 基于用户名和密码创建UsernamePasswordAuthenticationToken实例
		UsernamePasswordAuthenticationToken request = new UsernamePasswordAuthenticationToken(
				username, password);

		try {
		    // 使用AuthenticationManager处理身份验证请求
		    // 如果验证成功,则返回授予的权限集合
			return authenticationManager.authenticate(request).getAuthorities();
		}
		catch (AuthenticationException authEx) {
			throw new RemoteAuthenticationException(authEx.getMessage());
		}
	}

    // 返回authenticationManager属性
	protected AuthenticationManager getAuthenticationManager() {
		return authenticationManager;
	}

    // 设置authenticationManager属性
	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}
}
PreAuthenticatedAuthenticationProvider

处理预验证的验证请求。 该请求通常来自AbstractPreAuthenticatedProcessingFilter的子类。此身份验证提供程序不会对身份验证请求执行任何检查,因为它们应该已经过预身份验证。但是,例如AuthenticationUserDetailsS​​ervice实现(允许基于Authentication对象加载UserDetails对象的接口,用于为经过身份验证的用户加载UserDetails)可能仍会引发UsernameNotFoundException。

public class PreAuthenticatedAuthenticationProvider implements AuthenticationProvider,
		InitializingBean, Ordered {
	private static final Log logger = LogFactory
			.getLog(PreAuthenticatedAuthenticationProvider.class);

    // 用于为经过身份验证的用户加载UserDetails
	private AuthenticationUserDetailsService preAuthenticatedUserDetailsService = null;
	// 用于检查加载的UserDetails对象的状态
	private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
	// 当令牌(验证请求)被拒绝(验证失败)时是否抛出异常
	private boolean throwExceptionWhenTokenRejected = false;
    // 默认值,与无序相同
	private int order = -1; 

	
	public void afterPropertiesSet() {
		Assert.notNull(preAuthenticatedUserDetailsService,
				"An AuthenticationUserDetailsService must be set");
	}

	
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		// 是否支持该Authentication实例
		if (!supports(authentication.getClass())) {
			return null;
		}

		if (logger.isDebugEnabled()) {
			logger.debug("PreAuthenticated authentication request: " + authentication);
		}

        // 主体为空
		if (authentication.getPrincipal() == null) {
			logger.debug("No pre-authenticated principal found in request.");

            // 是否需要抛出异常
			if (throwExceptionWhenTokenRejected) {
				throw new BadCredentialsException(
						"No pre-authenticated principal found in request.");
			}
			// 验证失败
			return null;
		}

        // 凭据为空
		if (authentication.getCredentials() == null) {
			logger.debug("No pre-authenticated credentials found in request.");
 
            // 是否需要抛出异常
			if (throwExceptionWhenTokenRejected) {
				throw new BadCredentialsException(
						"No pre-authenticated credentials found in request.");
			}
			// 验证失败
			return null;
		}
        // 使用AuthenticationUserDetailsService为经过身份验证的用户加载UserDetails
		UserDetails ud = preAuthenticatedUserDetailsService
				.loadUserDetails((PreAuthenticatedAuthenticationToken) authentication);
        // 检查加载的UserDetails对象的状态
		userDetailsChecker.check(ud);
        // 根据加载的UserDetails对象和authentication对象创建PreAuthenticatedAuthenticationToken实例
        // 该实例用于返回,作为验证结果
		PreAuthenticatedAuthenticationToken result = new PreAuthenticatedAuthenticationToken(
				ud, authentication.getCredentials(), ud.getAuthorities());
		// 给验证结果设置验证请求的详细信息
		result.setDetails(authentication.getDetails());

		return result;
	}

	
	public final boolean supports(Class authentication) {
		return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
	}

	
	public void setPreAuthenticatedUserDetailsService(
			AuthenticationUserDetailsService uds) {
		this.preAuthenticatedUserDetailsService = uds;
	}

	
	public void setThrowExceptionWhenTokenRejected(boolean throwExceptionWhenTokenRejected) {
		this.throwExceptionWhenTokenRejected = throwExceptionWhenTokenRejected;
	}

	
	public void setUserDetailsChecker(UserDetailsChecker userDetailsChecker) {
		Assert.notNull(userDetailsChecker, "userDetailsChecker cannot be null");
		this.userDetailsChecker = userDetailsChecker;
	}

    // 返回order属性
	public int getOrder() {
		return order;
	}

    // 设置order属性
	public void setOrder(int i) {
		order = i;
	}
}
RunAsImplAuthenticationProvider

可以对RunAsUserToken进行身份验证的AuthenticationProvider实现。与RunAsImplAuthenticationProvider的密钥匹配的哈希码的任何RunAsUserToken实例视为有效。如果密钥不匹配,则会抛出BadCredentialsException。

public class RunAsImplAuthenticationProvider implements InitializingBean,
		AuthenticationProvider, MessageSourceAware {
    // 用于访问来自MessageSource的消息 
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	// 识别Authentication实例是否由授权客户生成的key
	private String key;

	// 检查key属性是否为null
	public void afterPropertiesSet() {
		Assert.notNull(key,
				"A Key is required and should match that configured for the RunAsManagerImpl");
	}

    // 进行验证
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		// 转换成RunAsUserToken实例
		RunAsUserToken token = (RunAsUserToken) authentication;
        // 与RunAsImplAuthenticationProvider的密钥匹配的哈希码的任何RunAsUserToken实例视为有效
		if (token.getKeyHash() == key.hashCode()) {
			return authentication;
		}
		else {
			throw new BadCredentialsException(messages.getMessage(
					"RunAsImplAuthenticationProvider.incorrectKey",
					"The presented RunAsUserToken does not contain the expected key"));
		}
	}
    // 返回key属性
	public String getKey() {
		return key;
	}
    // 设置key属性
	public void setKey(String key) {
		this.key = key;
	}
    // 设置messages属性
	public void setMessageSource(MessageSource messageSource) {
		this.messages = new MessageSourceAccessor(messageSource);
	}
    // 支持RunAsUserToken类型
	public boolean supports(Class authentication) {
		return RunAsUserToken.class.isAssignableFrom(authentication);
	}
}
AbstractUserDetailsAuthenticationProvider

一个基本的AuthenticationProvider,它允许子类覆盖和使用UserDetails对象。该类旨在响应UsernamePasswordAuthenticationToken身份验证请求。成功验证后,将创建一个UsernamePasswordAuthenticationToken并将其返回给调用者。

通过存储放置在UserCache中的UserDetails对象来处理缓存。这确保可以验证具有相同用户名的后续请求,而无需查询UserDetailsService。需要注意的是,如果用户出现密码错误,将查询UserDetailsService以确认是否使用了最新密码进行比较。只有无状态应用程序才可能需要缓存。例如,在普通的Web应用程序中, SecurityContext存储在用户的会话中,并且用户不会在每个请求上重新进行身份验证。因此,默认缓存实现是NullUserCache。

public abstract class AbstractUserDetailsAuthenticationProvider implements
		AuthenticationProvider, InitializingBean, MessageSourceAware {

	protected final Log logger = LogFactory.getLog(getClass());
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private UserCache userCache = new NullUserCache();
	private boolean forcePrincipalAsString = false;
	protected boolean hideUserNotFoundExceptions = true;
	private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks();
	private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks();
	private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();

	
	protected abstract void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException;

	public final void afterPropertiesSet() throws Exception {
		Assert.notNull(this.userCache, "A user cache must be set");
		Assert.notNull(this.messages, "A message source must be set");
		doAfterPropertiesSet();
	}

    // 进行验证
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
				() -> messages.getMessage(
						"AbstractUserDetailsAuthenticationProvider.onlySupports",
						"only UsernamePasswordAuthenticationToken is supported"));

		// 获取用户名
		String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"
				: authentication.getName();

		boolean cacheWasUsed = true;
		// 基于用户名,获取UserDetails实例
		UserDetails user = this.userCache.getUserFromCache(username);
        // 没有该用户
		if (user == null) {
			cacheWasUsed = false;

			try {
			    // 基于用户名和验证请求加载UserDetails
				user = retrieveUser(username,
						(UsernamePasswordAuthenticationToken) authentication);
			}
			catch (UsernameNotFoundException notFound) {
				logger.debug("User '" + username + "' not found");

				if (hideUserNotFoundExceptions) {
					throw new BadCredentialsException(messages.getMessage(
							"AbstractUserDetailsAuthenticationProvider.badCredentials",
							"Bad credentials"));
				}
				else {
					throw notFound;
				}
			}

			Assert.notNull(user,
					"retrieveUser returned null - a violation of the interface contract");
		}

		try {
		    // 验证前,检查UserDetails
			preAuthenticationChecks.check(user);
			// 进行验证,如检查密码是否匹配
			additionalAuthenticationChecks(user,
					(UsernamePasswordAuthenticationToken) authentication);
		}
		catch (AuthenticationException exception) {
		    // 如果使用的是缓存
		    // 并且出现问题,则应该使用最新数据进行重试
			if (cacheWasUsed) {
				cacheWasUsed = false;
				user = retrieveUser(username,
						(UsernamePasswordAuthenticationToken) authentication);
				preAuthenticationChecks.check(user);
				additionalAuthenticationChecks(user,
						(UsernamePasswordAuthenticationToken) authentication);
			}
			else {
				throw exception;
			}
		}
        // 验证后,检查UserDetails
		postAuthenticationChecks.check(user);
        // 更新缓存
		if (!cacheWasUsed) {
			this.userCache.putUserInCache(user);
		}

		Object principalToReturn = user;
        // 强制Principal作为字符串
		if (forcePrincipalAsString) {
			principalToReturn = user.getUsername();
		}
        // 验证成功后,创建Authentication实例用于返回,表示验证结果
		return createSuccessAuthentication(principalToReturn, authentication, user);
	}

	
	protected Authentication createSuccessAuthentication(Object principal,
			Authentication authentication, UserDetails user) {
		// 确保返回用户提供的原始凭据
		// 以便后续尝试使用编码密码也能成功
		// 还要确保返回原始的getDetails()
		// 以便缓存到期后的未来身份验证事件包含详细信息
		UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
				principal, authentication.getCredentials(),
				authoritiesMapper.mapAuthorities(user.getAuthorities()));
		result.setDetails(authentication.getDetails());

		return result;
	}

	protected void doAfterPropertiesSet() throws Exception {
	}

    ...

	
	protected abstract UserDetails retrieveUser(String username,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException;

	public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
		this.forcePrincipalAsString = forcePrincipalAsString;
	}

	
	public void setHideUserNotFoundExceptions(boolean hideUserNotFoundExceptions) {
		this.hideUserNotFoundExceptions = hideUserNotFoundExceptions;
	}

	...
    
    // 支持UsernamePasswordAuthenticationToken类型
	public boolean supports(Class authentication) {
		return (UsernamePasswordAuthenticationToken.class
				.isAssignableFrom(authentication));
	}

    // 默认用于验证前UserDetails检查的UserDetailsChecker实现
	private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
		public void check(UserDetails user) {
			if (!user.isAccountNonLocked()) {
				logger.debug("User account is locked");

				throw new LockedException(messages.getMessage(
						"AbstractUserDetailsAuthenticationProvider.locked",
						"User account is locked"));
			}

			if (!user.isEnabled()) {
				logger.debug("User account is disabled");

				throw new DisabledException(messages.getMessage(
						"AbstractUserDetailsAuthenticationProvider.disabled",
						"User is disabled"));
			}

			if (!user.isAccountNonExpired()) {
				logger.debug("User account is expired");

				throw new AccountExpiredException(messages.getMessage(
						"AbstractUserDetailsAuthenticationProvider.expired",
						"User account has expired"));
			}
		}
	}
    // 默认用于验证后UserDetails检查的UserDetailsChecker实现
	private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
		public void check(UserDetails user) {
			if (!user.isCredentialsNonExpired()) {
				logger.debug("User account credentials have expired");

				throw new CredentialsExpiredException(messages.getMessage(
						"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
						"User credentials have expired"));
			}
		}
	}
}
DaoAuthenticationProvider

从UserDetailsService加载用户详细信息的AuthenticationProvider实现。

Spring Security:用户服务UserDetailsService源码分析

public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
	
	
	private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
    // 密码编码器
	private PasswordEncoder passwordEncoder;

	
	private volatile String userNotFoundEncodedPassword;
    // 用于加载用户详细信息
	private UserDetailsService userDetailsService;
    // 用于更改UserDetails密码的API
	private UserDetailsPasswordService userDetailsPasswordService;

    // 构造器
    // 使用PasswordEncoderFactories.createDelegatingPasswordEncoder()的值设置密码编码器
	public DaoAuthenticationProvider() {
		setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
	}

    // 验证检查
	@SuppressWarnings("deprecation")
	protected void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
		// 如果验证请求的凭据(比如密码)为null,则抛出异常
		if (authentication.getCredentials() == null) {
			logger.debug("Authentication failed: no credentials provided");

			throw new BadCredentialsException(messages.getMessage(
					"AbstractUserDetailsAuthenticationProvider.badCredentials",
					"Bad credentials"));
		}
        // 获取密码
		String presentedPassword = authentication.getCredentials().toString();
        // 验证请求的密码是否和用户(基于验证请求加载)的密码匹配
		if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
			logger.debug("Authentication failed: password does not match stored value");

			throw new BadCredentialsException(messages.getMessage(
					"AbstractUserDetailsAuthenticationProvider.badCredentials",
					"Bad credentials"));
		}
	}

    // 检查userDetailsService属性是否为null
	protected void doAfterPropertiesSet() {
		Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
	}

    // 基于验证请求加载UserDetails(用户)
	protected final UserDetails retrieveUser(String username,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
		prepareTimingAttackProtection();
		try {
		    // 基于用户名,使用UserDetailsService加载UserDetails
			UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
			// 加载不到UserDetails,则抛出异常
			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);
		}
	}

    // 验证成功后,创建Authentication实例用于表示验证请求的结果
	@Override
	protected Authentication createSuccessAuthentication(Object principal,
			Authentication authentication, UserDetails user) {
		// 是否需要再次对编码的密码进行编码(为了更好的安全性)
		boolean upgradeEncoding = this.userDetailsPasswordService != null
				&& this.passwordEncoder.upgradeEncoding(user.getPassword());
		if (upgradeEncoding) {
			String presentedPassword = authentication.getCredentials().toString();
			// 再次编码
			String newPassword = this.passwordEncoder.encode(presentedPassword);
			// 使用UserDetailsPasswordService更新用户的密码
			user = this.userDetailsPasswordService.updatePassword(user, newPassword);
		}
		// 通过调用super来返回
		return super.createSuccessAuthentication(principal, authentication, user);
	}

    // 保护方法,避免SEC-2056(黑客嗅探用户是否存在)
	private void prepareTimingAttackProtection() {
		if (this.userNotFoundEncodedPassword == null) {
			this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
		}
	}
    // 用户不存在时,将使用userNotFoundEncodedPassword进行密码匹配
    // 
	private void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication) {
		if (authentication.getCredentials() != null) {
			String presentedPassword = authentication.getCredentials().toString();
			this.passwordEncoder.matches(presentedPassword, this.userNotFoundEncodedPassword);
		}
	}

	
	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
		this.passwordEncoder = passwordEncoder;
		this.userNotFoundEncodedPassword = null;
	}
	...
}

还有三个AuthenticationProvider接口的实现类,用于验证JaasAuthenticationToken,大家可以自行阅读源码,这里就不进行介绍了。

身份验证提供程序AuthenticationProvider介绍就到这里,如果博主有说错的地方或者大家有不同的见解,欢迎大家评论补充。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/710573.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号