|
@@ -19,9 +19,12 @@ import com.usky.system.service.MceReceiveService;
|
|
|
import eu.bitwalker.useragentutils.UserAgent;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
import static com.usky.common.core.utils.ip.IpUtils.getIpAddr;
|
|
|
|
|
@@ -30,8 +33,8 @@ import static com.usky.common.core.utils.ip.IpUtils.getIpAddr;
|
|
|
* @author: XiaoYu
|
|
|
* @date: 2024/08/20 13:58
|
|
|
*/
|
|
|
-public class AsyncFactory
|
|
|
-{
|
|
|
+@Component
|
|
|
+public class AsyncFactory {
|
|
|
private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
|
|
|
|
|
|
private static final MceReceiveService mceReceiveService = SpringContextUtils.getBean(MceReceiveService.class);
|
|
@@ -81,11 +84,11 @@ public class AsyncFactory
|
|
|
if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
|
|
|
logininfor.setStatus(String.valueOf(Constants.LOGIN_SUCCESS_STATUS)); // 使用String.valueOf进行转换
|
|
|
|
|
|
- // 如果登录成功,发送微信公众号消息,删除超出规定历史token
|
|
|
+ // 如果登录成功,发送微信公众号消息
|
|
|
if (Constants.LOGIN_SUCCESS.equals(status)) {
|
|
|
sendWeChatMessage(logininfor);
|
|
|
// 保留用户相同OS和Browser的最新两条token,删除其他所有token
|
|
|
- retainLatestToken(username);
|
|
|
+ SpringContextUtils.getBean(AsyncFactory.class).asyncRetainLatestToken(username);
|
|
|
}
|
|
|
} else if (Constants.LOGIN_FAIL.equals(status)) {
|
|
|
logininfor.setStatus(String.valueOf(Constants.LOGIN_FAIL_STATUS)); // 使用String.valueOf进行转换
|
|
@@ -95,10 +98,8 @@ public class AsyncFactory
|
|
|
SpringContextUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
|
|
|
}
|
|
|
|
|
|
- public static String getBlock(Object msg)
|
|
|
- {
|
|
|
- if (msg == null)
|
|
|
- {
|
|
|
+ public static String getBlock(Object msg) {
|
|
|
+ if (msg == null) {
|
|
|
msg = "";
|
|
|
}
|
|
|
return "[" + msg.toString() + "]";
|
|
@@ -127,7 +128,25 @@ public class AsyncFactory
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 保留用户相同OS和Browser的最新两条token,删除其他历史token
|
|
|
+ * 异步清理历史token
|
|
|
+ *
|
|
|
+ * @param username 用户名
|
|
|
+ */
|
|
|
+ @Async
|
|
|
+ public void asyncRetainLatestToken(String username) {
|
|
|
+ try {
|
|
|
+ // 等待2秒
|
|
|
+ TimeUnit.SECONDS.sleep(2);
|
|
|
+ // 调用清理token的方法
|
|
|
+ retainLatestToken(username);
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ sys_user_logger.error("异步清理token时发生错误", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保留用户相同OS的最新一个token,删除其他历史token
|
|
|
*
|
|
|
* @param username 用户名
|
|
|
*/
|
|
@@ -150,6 +169,7 @@ public class AsyncFactory
|
|
|
// 检查键是否存在并且未过期
|
|
|
if (redisService.hasKey(key)) {
|
|
|
LoginUser user = redisService.getCacheObject(key);
|
|
|
+ sys_user_logger.info("从Redis获取的LoginUser对象: {}", user);
|
|
|
if (user != null && username.equals(user.getUsername())) {
|
|
|
userTokens.put(key, user);
|
|
|
}
|
|
@@ -161,24 +181,24 @@ public class AsyncFactory
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 分组逻辑:根据OS和Browser分组
|
|
|
+ // 分组逻辑:根据OS分组
|
|
|
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);
|
|
|
+ groupedTokens.computeIfAbsent(os, 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++) {
|
|
|
+
|
|
|
+ // 只保留最新的一个token,其余的都添加到tokensToDelete列表中
|
|
|
+ for (int i = 1; i < entryList.size(); i++) {
|
|
|
String keyToDelete = entryList.get(i).getKey();
|
|
|
tokensToDelete.add(keyToDelete);
|
|
|
}
|
|
@@ -200,7 +220,7 @@ public class AsyncFactory
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- sys_user_logger.info("用户 {} 的token已清理,仅保留最新的两条token: 已删除{}个", username, tokensToDelete.size());
|
|
|
+ sys_user_logger.info("用户 {} 的token已清理,仅保留每种OS的最新token: 已删除{}个", username, tokensToDelete.size());
|
|
|
} catch (Exception ex) {
|
|
|
sys_user_logger.error("清理用户 {} 的token时发生错误", username, ex);
|
|
|
}
|