Spring?Security中用戶名和密碼的驗證完整流程
首先創(chuàng)建了一個UsernamePasswordAuthenticationToken對象,這是Spring Security中用于表示基于用戶名和密碼的認證請求的一個類。這個對象被初始化時,接收了兩個參數(shù):username(用戶名)和password(密碼)。這兩個參數(shù)代表了用戶嘗試登錄時提供的憑證。
接下來,通過調(diào)用authenticationManager的authenticate方法,并傳入前面創(chuàng)建的authenticationToken對象,來執(zhí)行認證過程。authenticationManager是Spring Security中的一個核心接口,它負責處理認證請求。在調(diào)用authenticate方法時,Spring Security會基于配置的安全策略(比如從數(shù)據(jù)庫、LDAP服務(wù)器或其他認證源中檢索用戶信息,并驗證提供的密碼是否正確)來驗證用戶提供的憑證是否有效
如果認證成功,authenticate方法會返回一個填充了用戶權(quán)限等詳細信息的Authentication對象。這個對象代表了認證成功后的用戶會話,包含了用戶的身份信息、權(quán)限、是否已記住我(remember-me)等詳細信息。
如果認證失敗,authenticate方法會拋出一個AuthenticationException異常,這通常意味著提供的用戶名或密碼不正確,或者用戶賬戶處于鎖定、禁用等狀態(tài)。
/**
* 登錄驗證
*
* @param username 用戶名
* @param password 密碼
* @param code 驗證碼
* @param uuid 唯一標識
* @return 結(jié)果
*/
public String login(String username, String password, String code, String uuid)
{
// 驗證碼校驗
validateCaptcha(username, code, uuid);
// 登錄前置校驗
loginPreCheck(username, password);
// 用戶驗證
Authentication authentication = null;
try
{
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
AuthenticationContextHolder.setContext(authenticationToken);
// 該方法會去調(diào)用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager.authenticate(authenticationToken);
}
catch (Exception e)
{
if (e instanceof BadCredentialsException)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
else
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
}
finally
{
//清理認證上下文,確保線程上下文中的認證信息被清除,避免潛在的內(nèi)存泄漏或安全問題
AuthenticationContextHolder.clearContext();
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
//從認證成功的Authentication對象中獲取Principal,并將其強制轉(zhuǎn)換為LoginUser對象。LoginUser是一個自定義類,通常包含用戶的基本信息和權(quán)限信息
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
//調(diào)用recordLoginInfo方法記錄用戶的登錄信息,例如登錄時間、IP地址等
recordLoginInfo(loginUser.getUserId());
// 生成token,為用戶生成一個Token,并返回該Token。Token通常用于后續(xù)的用戶身份驗證和授權(quán)
return tokenService.createToken(loginUser);
}驗證碼校驗方法
/**
* 校驗驗證碼
*
* @param username 用戶名
* @param code 驗證碼
* @param uuid 唯一標識
* @return 結(jié)果
*/
public void validateCaptcha(String username, String code, String uuid)
{
boolean captchaEnabled = configService.selectCaptchaEnabled();
if (captchaEnabled)
{
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
String captcha = redisCache.getCacheObject(verifyKey);
if (captcha == null)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
throw new CaptchaExpireException();
}
redisCache.deleteObject(verifyKey);
if (!code.equalsIgnoreCase(captcha))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
}
}
}用戶名和密碼校驗代碼
/**
* 登錄前置校驗
* @param username 用戶名
* @param password 用戶密碼
*/
public void loginPreCheck(String username, String password)
{
// 用戶名或密碼為空 錯誤
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
throw new UserNotExistsException();
}
// 密碼如果不在指定范圍內(nèi) 錯誤
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
// 用戶名不在指定范圍內(nèi) 錯誤
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
// IP黑名單校驗
String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
throw new BlackListException();
}
}記錄登錄信息代碼
/**
* 記錄登錄信息
*
* @param userId 用戶ID
*/
public void recordLoginInfo(Long userId)
{
SysUser sysUser = new SysUser();
sysUser.setUserId(userId);
sysUser.setLoginIp(IpUtils.getIpAddr());
sysUser.setLoginDate(DateUtils.getNowDate());
userService.updateUserProfile(sysUser);
}UserDetailsServiceImpl實現(xiàn)類的代碼,UserDetailsService是java自帶的類,UserDetailsServiceImpl繼承UserDetailsService的loadUserByUsername方法
/**
* 用戶驗證處理
*
* @author ruoyi
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService
{
private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
@Autowired
private ISysUserService userService;
@Autowired
private SysPasswordService passwordService;
@Autowired
private SysPermissionService permissionService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
SysUser user = userService.selectUserByUserName(username);
if (StringUtils.isNull(user))
{
log.info("登錄用戶:{} 不存在.", username);
throw new ServiceException(MessageUtils.message("user.not.exists"));
}
else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
{
log.info("登錄用戶:{} 已被刪除.", username);
throw new ServiceException(MessageUtils.message("user.password.delete"));
}
else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
{
log.info("登錄用戶:{} 已被停用.", username);
throw new ServiceException(MessageUtils.message("user.blocked"));
}
passwordService.validate(user);
return createLoginUser(user);
}
public UserDetails createLoginUser(SysUser user)
{
return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
}
}到此這篇關(guān)于在Spring Security中,用戶名和密碼的驗證流程的文章就介紹到這了,更多相關(guān)Spring Security用戶名和密碼驗證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
HttpServletResponse亂碼問題_動力節(jié)點Java學院整理
這篇文章主要介紹了HttpServletResponse亂碼問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07
Java使用選擇排序法對數(shù)組排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了Java使用選擇排序法對數(shù)組排序?qū)崿F(xiàn)代碼,需要的朋友可以參考下2014-02-02

