|
@@ -3,24 +3,25 @@ package com.usky.system.service.util;
|
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
import com.alibaba.fastjson.JSON;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
+import com.ruoyi.common.core.constant.CacheConstants;
|
|
import com.ruoyi.common.core.constant.Constants;
|
|
import com.ruoyi.common.core.constant.Constants;
|
|
-import com.ruoyi.common.core.utils.ServletUtils;
|
|
|
|
import com.ruoyi.common.core.utils.StringUtils;
|
|
import com.ruoyi.common.core.utils.StringUtils;
|
|
-import com.ruoyi.common.core.utils.ip.IpUtils;
|
|
|
|
import com.usky.common.core.util.SpringContextUtils;
|
|
import com.usky.common.core.util.SpringContextUtils;
|
|
|
|
+import com.usky.common.log.aspect.AddressUtils;
|
|
|
|
+import com.usky.common.redis.core.RedisService;
|
|
import com.usky.system.domain.MceRequestVO;
|
|
import com.usky.system.domain.MceRequestVO;
|
|
import com.usky.system.domain.SysLogininfor;
|
|
import com.usky.system.domain.SysLogininfor;
|
|
import com.usky.system.domain.SysUser;
|
|
import com.usky.system.domain.SysUser;
|
|
import com.usky.system.mapper.SysUserMapper;
|
|
import com.usky.system.mapper.SysUserMapper;
|
|
|
|
+import com.usky.system.model.LoginUser;
|
|
import com.usky.system.service.ISysLogininforService;
|
|
import com.usky.system.service.ISysLogininforService;
|
|
-import com.usky.system.service.ISysUserService;
|
|
|
|
import com.usky.system.service.MceReceiveService;
|
|
import com.usky.system.service.MceReceiveService;
|
|
import eu.bitwalker.useragentutils.UserAgent;
|
|
import eu.bitwalker.useragentutils.UserAgent;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
-import java.util.Collections;
|
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
|
import static com.usky.common.core.utils.ip.IpUtils.getIpAddr;
|
|
import static com.usky.common.core.utils.ip.IpUtils.getIpAddr;
|
|
|
|
|
|
@@ -80,9 +81,11 @@ public class AsyncFactory
|
|
if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
|
|
if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
|
|
logininfor.setStatus(String.valueOf(Constants.LOGIN_SUCCESS_STATUS)); // 使用String.valueOf进行转换
|
|
logininfor.setStatus(String.valueOf(Constants.LOGIN_SUCCESS_STATUS)); // 使用String.valueOf进行转换
|
|
|
|
|
|
- // 如果登录成功,发送微信公众号消息
|
|
|
|
|
|
+ // 如果登录成功,发送微信公众号消息,删除超出规定历史token
|
|
if (Constants.LOGIN_SUCCESS.equals(status)) {
|
|
if (Constants.LOGIN_SUCCESS.equals(status)) {
|
|
sendWeChatMessage(logininfor);
|
|
sendWeChatMessage(logininfor);
|
|
|
|
+ // 保留用户相同OS和Browser的最新两条token,删除其他所有token
|
|
|
|
+ retainLatestToken(username);
|
|
}
|
|
}
|
|
} else if (Constants.LOGIN_FAIL.equals(status)) {
|
|
} else if (Constants.LOGIN_FAIL.equals(status)) {
|
|
logininfor.setStatus(String.valueOf(Constants.LOGIN_FAIL_STATUS)); // 使用String.valueOf进行转换
|
|
logininfor.setStatus(String.valueOf(Constants.LOGIN_FAIL_STATUS)); // 使用String.valueOf进行转换
|
|
@@ -122,4 +125,84 @@ public class AsyncFactory
|
|
mceRequestVO.setIpAddress(logininfor.getIpaddr());
|
|
mceRequestVO.setIpAddress(logininfor.getIpaddr());
|
|
mceReceiveService.addMceReceive(mceRequestVO);
|
|
mceReceiveService.addMceReceive(mceRequestVO);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 保留用户相同OS和Browser的最新两条token,删除其他历史token
|
|
|
|
+ *
|
|
|
|
+ * @param username 用户名
|
|
|
|
+ */
|
|
|
|
+ private static void retainLatestToken(String username) {
|
|
|
|
+ RedisService redisService = SpringContextUtils.getBean(RedisService.class);
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ // 获取所有与该用户相关的token键
|
|
|
|
+ String pattern = CacheConstants.LOGIN_TOKEN_KEY + "*";
|
|
|
|
+ Collection<String> keys = redisService.keys(pattern);
|
|
|
|
+ if (keys == null || keys.isEmpty()) {
|
|
|
|
+ sys_user_logger.warn("Redis密钥为null或为空");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 存储该用户的token及其对应的LoginUser对象
|
|
|
|
+ Map<String, LoginUser> userTokens = new HashMap<>();
|
|
|
|
+
|
|
|
|
+ for (String key : keys) {
|
|
|
|
+ // 检查键是否存在并且未过期
|
|
|
|
+ if (redisService.hasKey(key)) {
|
|
|
|
+ LoginUser user = redisService.getCacheObject(key);
|
|
|
|
+ if (user != null && username.equals(user.getUsername())) {
|
|
|
|
+ userTokens.put(key, user);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (userTokens.isEmpty()) {
|
|
|
|
+ sys_user_logger.warn("未找到用户 {} 的任何token", username);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 分组逻辑:根据OS和Browser分组
|
|
|
|
+ Map<String, List<Map.Entry<String, LoginUser>>> groupedTokens = new HashMap<>();
|
|
|
|
+ for (Map.Entry<String, LoginUser> entry : userTokens.entrySet()) {
|
|
|
|
+ LoginUser loginUser = entry.getValue();
|
|
|
|
+ String os = StringUtils.isEmpty(loginUser.getOs()) ? "未知" : loginUser.getOs();
|
|
|
|
+ String browser = StringUtils.isEmpty(loginUser.getBrowser()) ? "未知" : loginUser.getBrowser();
|
|
|
|
+ String osBrowserKey = os + "-" + browser;
|
|
|
|
+ groupedTokens.computeIfAbsent(osBrowserKey, k -> new ArrayList<>()).add(entry);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 删除逻辑:保留最新的两条token,删除其他token
|
|
|
|
+ List<String> tokensToDelete = new ArrayList<>();
|
|
|
|
+ for (List<Map.Entry<String, LoginUser>> entryList : groupedTokens.values()) {
|
|
|
|
+ // 按照登录时间排序,保留最新的两条token
|
|
|
|
+ entryList.sort((e1, e2) ->
|
|
|
|
+ e2.getValue().getLoginTime().compareTo(e1.getValue().getLoginTime())
|
|
|
|
+ );
|
|
|
|
+ for (int i = 3; i < entryList.size(); i++) {
|
|
|
|
+ String keyToDelete = entryList.get(i).getKey();
|
|
|
|
+ tokensToDelete.add(keyToDelete);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 删除其他token
|
|
|
|
+ sys_user_logger.info("要删除的token列表: {}", tokensToDelete);
|
|
|
|
+ for (String keyToDelete : tokensToDelete) {
|
|
|
|
+ if (keyToDelete != null) {
|
|
|
|
+ // 再次检查键是否存在
|
|
|
|
+ if (redisService.hasKey(keyToDelete)) {
|
|
|
|
+ boolean deleted = redisService.deleteObject(keyToDelete);
|
|
|
|
+ sys_user_logger.info("Deleted Token Key: " + keyToDelete + ", Result: " + deleted);
|
|
|
|
+ } else {
|
|
|
|
+ sys_user_logger.warn("尝试删除的token键 {} 不存在,跳过删除操作", keyToDelete);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ sys_user_logger.warn("尝试删除的token键为null,跳过删除操作");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ sys_user_logger.info("用户 {} 的token已清理,仅保留最新的两条token: 已删除{}个", username, tokensToDelete.size());
|
|
|
|
+ } catch (Exception ex) {
|
|
|
|
+ sys_user_logger.error("清理用户 {} 的token时发生错误", username, ex);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|