Spring Security登录的简单解析
- 1.自己写的登录
- 2.进入`authenticationManager.authenticate(authenticationToken);`
- 3 进入`result = provider.authenticate(authentication);`
- 4 进入` user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);`
- 5 进入 `UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);`
- 注:
1.自己写的登录
public TokenVo login(String username, String password) {//封装 AuthenticationUsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);//认证用户Authentication authenticate = authenticationManager.authenticate(authenticationToken);if (authenticate == null) {throw new RuntimeException("认证失败!");}//获取认证用户信息UserDetailsInfo userDetailsInfo = (UserDetailsInfo) authenticate.getPrincipal();//认证通过,生成jwtTokenVo tokenVo=new TokenVo();String token = jwtTokenUtil.generateToken(userDetailsInfo);tokenVo.setToken(token);tokenVo.setExpireTime(jwtTokenUtil.expiration);redisCache.setCacheObject(token, userDetailsInfo, jwtTokenUtil.expiration, TimeUnit.SECONDS);return tokenVo;}
2.进入authenticationManager.authenticate(authenticationToken);
其所属类是ProviderManager implements AuthenticationManage
public Authentication authenticate(Authentication authentication) throws AuthenticationException {Class<? extends Authentication> toTest = authentication.getClass();AuthenticationException lastException = null;AuthenticationException parentException = null;Authentication result = null;Authentication parentResult = null;int currentPosition = 0;int size = this.providers.size();// 遍历所有的验证提供者for (AuthenticationProvider provider : getProviders()) {// 判断当前验证提供者是否支持传入的Authentication对象的类型if (!provider.supports(toTest)) {continue;}// 打印正在使用的验证提供者和当前位置logger.trace(LogMessage.format("Authenticating request with %s (%d/%d)",provider.getClass().getSimpleName(), ++currentPosition, size));try {// 调用当前验证提供者的authenticate方法进行身份验证result = provider.authenticate(authentication);// 如果验证成功,复制验证结果的详细信息到原始的Authentication对象中if (result != null) {//copyDetails(authentication, result);break;}} catch (AccountStatusException | InternalAuthenticationServiceException ex) {// 准备抛出异常并中止验证过程prepareException(ex, authentication);throw ex;} catch (AuthenticationException ex) {lastException = ex;}}// 如果当前验证提供者未能验证成功,并且存在父验证管理器,则尝试使用父验证管理器进行验证if (result == null && this.parent != null) {try {parentResult = this.parent.authenticate(authentication);result = parentResult;} catch (ProviderNotFoundException ex) {// 忽略该异常} catch (AuthenticationException ex) {parentException = ex;lastException = ex;}}// 如果验证成功,执行一些后续操作,如擦除验证结果中的敏感信息,并发布身份验证成功的事件if (result != null) {//((CredentialsContainer) result).eraseCredentials();//if (parentResult == null) {// this.eventPublisher.publishAuthenticationSuccess(result);//}return result;}// 如果最后一个异常为空,则创建一个ProviderNotFoundException异常if (lastException == null) {lastException = new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound",new Object[] { toTest.getName() }, "No AuthenticationProvider found for {0}"));}// 如果父验证管理器的验证异常为空,则准备抛出最后一个异常if (parentException == null) {prepareException(lastException, authentication);}// 抛出最后一个异常throw lastException;
}
3 进入result = provider.authenticate(authentication);
其所属类public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider,
执行
// 确保传入的Authentication对象是UsernamePasswordAuthenticationToken的实例
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,() -> this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports","Only UsernamePasswordAuthenticationToken is supported"));// 获取用户名
String username = determineUsername(authentication);boolean cacheWasUsed = true;
// 从缓存中获取用户详细信息
UserDetails user = this.userCache.getUserFromCache(username);if (user == null) {cacheWasUsed = false;try {// 从数据源中检索用户详细信息user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);} catch (UsernameNotFoundException ex) {this.logger.debug("Failed to find user '" + username + "'");if (!this.hideUserNotFoundExceptions) {throw ex;}// 如果用户名未找到,抛出BadCredentialsException异常throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));}// 确保retrieveUser方法的实现没有返回nullAssert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
}try {// 对用户进行预身份验证检查this.preAuthenticationChecks.check(user);// 对用户进行额外的身份验证检查additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
} catch (AuthenticationException ex) {if (!cacheWasUsed) {throw ex;}// 如果出现问题,尝试再次进行身份验证检查,确保使用最新的数据(即不使用缓存)cacheWasUsed = false;user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);this.preAuthenticationChecks.check(user);additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
}// 对用户进行后身份验证检查
this.postAuthenticationChecks.check(user);if (!cacheWasUsed) {// 将用户详细信息放入缓存中this.userCache.putUserInCache(user);
}Object principalToReturn = user;
if (this.forcePrincipalAsString) {// 如果设置了forcePrincipalAsString为true,则返回用户名作为principalprincipalToReturn = user.getUsername();
}// 创建身份验证成功的Authentication对象
return createSuccessAuthentication(principalToReturn, authentication, user);
4 进入 user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
其所属类class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider
执行
/*** 从用户详细信息服务中检索用户详细信息。** @param username 用户名* @param authentication 用于身份验证的`UsernamePasswordAuthenticationToken`对象* @return 用户详细信息* @throws AuthenticationException 如果发生身份验证异常*/
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)throws AuthenticationException {// 准备防止时序攻击的措施prepareTimingAttackProtection();try {// 通过用户详细信息服务加载指定用户名的用户详细信息UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);if (loadedUser == null) {// 如果加载的用户详细信息为null,抛出InternalAuthenticationServiceException异常,违反了接口约定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) {// 抛出InternalAuthenticationServiceException异常,将原始异常信息作为其原因throw new InternalAuthenticationServiceException(ex.getMessage(), ex);}
}
5 进入 UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
调用自己写的loadUserByUsername();
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate SysUserMapper sysUserMapper;@Autowiredprivate PasswordEncoder passwordEncoder;@Override@Transactionalpublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {UserDetailsInfo userDetailsInfo = sysUserMapper.getUserInfoByUsername(username);if(userDetailsInfo == null){throw new UsernameNotFoundException("用戶不存在");}userDetailsInfo.setPassword(passwordEncoder.encode(userDetailsInfo.getPassword()));return userDetailsInfo;}
注:
用户名校验
密码校验