多设备登录修改

This commit is contained in:
cwchen 2025-09-29 13:46:48 +08:00
parent 81279a54d3
commit 560298ae7f
1 changed files with 68 additions and 11 deletions

View File

@ -27,7 +27,7 @@ import io.jsonwebtoken.SignatureAlgorithm;
/**
* token验证处理
*
*
* @author bonus
*/
@Component
@ -58,7 +58,7 @@ public class TokenService
/**
* 获取用户身份信息
*
*
* @return 用户信息
*/
public LoginUser getLoginUser(HttpServletRequest request)
@ -75,16 +75,23 @@ public class TokenService
String usernameFromJwt = (String) claims.get(Constants.JWT_USERNAME);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
if (StringUtils.isNull(user))
{
// login_tokens:{uuid} 已不存在视为会话被挤下线或已失效
// 为确保前端能提示其他设备登录在能解析出用户名时一律标记
// login_tokens:{uuid} 已不存在需要区分是过期还是被挤下线
if (StringUtils.isNotEmpty(usernameFromJwt))
{
request.setAttribute("forceLogoutByOtherDevice", Boolean.TRUE);
String mappedUuid = redisCache.getCacheObject(getUserTokenKey(usernameFromJwt));
if (StringUtils.isNotEmpty(mappedUuid) && !uuid.equals(mappedUuid))
{
// 用户名映射存在且指向其他uuid说明是被其他设备挤下线
request.setAttribute("forceLogoutByOtherDevice", Boolean.TRUE);
}
// 否则就是正常的token过期不需要设置特殊标记
}
return null;
}
// 单端在线校验username -> uuid 映射需要与当前token匹配
String username = user.getUsername();
String mappedUuid = redisCache.getCacheObject(getUserTokenKey(username));
@ -142,7 +149,7 @@ public class TokenService
/**
* 创建令牌
*
*
* @param loginUser 用户信息
* @return 令牌
*/
@ -164,7 +171,7 @@ public class TokenService
/**
* 验证令牌有效期相差不足20分钟自动刷新缓存
*
*
* @param loginUser 登录信息
* @return 令牌
*/
@ -180,7 +187,7 @@ public class TokenService
/**
* 刷新令牌有效期
*
*
* @param loginUser 登录信息
*/
public void refreshToken(LoginUser loginUser)
@ -202,7 +209,7 @@ public class TokenService
/**
* 设置用户代理信息
*
*
* @param loginUser 登录信息
*/
public void setUserAgent(LoginUser loginUser)
@ -297,6 +304,9 @@ public class TokenService
return getToken(ServletUtils.getRequest());
}
/**
* 根据token获取登录用户信息
*/
public LoginUser getLoginUser(String token){
if (StringUtils.isNotEmpty(token)){
try
@ -307,19 +317,23 @@ public class TokenService
String usernameFromJwt = (String) claims.get(Constants.JWT_USERNAME);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
if (StringUtils.isNull(user))
{
// 若login_tokens无此uuid检查用户名映射若映射存在且指向其他uuid则视为被其他设备挤下线
// 若login_tokens无此uuid检查用户名映射
if (StringUtils.isNotEmpty(usernameFromJwt))
{
String mappedUuid = redisCache.getCacheObject(getUserTokenKey(usernameFromJwt));
if (StringUtils.isNotEmpty(mappedUuid) && !uuid.equals(mappedUuid))
{
// 被其他设备挤下线
return null;
}
// 否则是正常过期返回null
}
return null;
}
String username = user.getUsername();
String mappedUuid = redisCache.getCacheObject(getUserTokenKey(username));
if (StringUtils.isEmpty(mappedUuid) || !uuid.equals(mappedUuid))
@ -351,4 +365,47 @@ public class TokenService
}
redisCache.setCacheObject(userTokenKey, uuid, expireTime, TimeUnit.MINUTES);
}
}
/**
* 检查token是否过期新增方法
*
* @param token token
* @return true-过期, false-未过期
*/
public boolean isTokenExpired(String token) {
try {
Claims claims = parseToken(token);
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
return StringUtils.isNull(user);
} catch (Exception e) {
log.error("检查token过期状态异常'{}'", e.getMessage());
return true;
}
}
/**
* 检查是否被其他设备挤下线新增方法
*
* @param token token
* @return true-被挤下线, false-未被挤下线
*/
public boolean isForceLogoutByOtherDevice(String token) {
try {
Claims claims = parseToken(token);
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String usernameFromJwt = (String) claims.get(Constants.JWT_USERNAME);
if (StringUtils.isNotEmpty(usernameFromJwt)) {
String mappedUuid = redisCache.getCacheObject(getUserTokenKey(usernameFromJwt));
// 如果用户名映射存在且指向其他uuid说明是被挤下线
return StringUtils.isNotEmpty(mappedUuid) && !uuid.equals(mappedUuid);
}
return false;
} catch (Exception e) {
log.error("检查是否被挤下线异常'{}'", e.getMessage());
return false;
}
}
}