From f991c73f56f35665bcbe8ce2252c04ea82032b10 Mon Sep 17 00:00:00 2001
From: hjl <1657978663@qq.com>
Date: 星期一, 27 五月 2024 18:06:31 +0800
Subject: [PATCH] feat: 修复登录bug;数据校验规则优化

---
 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java |  247 ++++++++++++++++++++++++++++++++++++------------
 1 files changed, 184 insertions(+), 63 deletions(-)

diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java
index a5af603..ca27eae 100644
--- a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java
+++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java
@@ -1,15 +1,9 @@
 package com.ruoyi.common.security.service;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import javax.servlet.http.HttpServletRequest;
-
-import com.ruoyi.system.api.model.LoginUserParent;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
+import com.alibaba.fastjson2.JSONObject;
 import com.ruoyi.common.core.constant.CacheConstants;
 import com.ruoyi.common.core.constant.SecurityConstants;
+import com.ruoyi.common.core.exception.user.StudyLoginException;
 import com.ruoyi.common.core.utils.JwtUtils;
 import com.ruoyi.common.core.utils.ServletUtils;
 import com.ruoyi.common.core.utils.StringUtils;
@@ -18,15 +12,23 @@
 import com.ruoyi.common.redis.service.RedisService;
 import com.ruoyi.common.security.utils.SecurityUtils;
 import com.ruoyi.system.api.model.LoginUser;
+import com.ruoyi.system.api.model.LoginUserParent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * token验证处理
- * 
+ *
  * @author ruoyi
  */
 @Component
-public class TokenService
-{
+public class TokenService {
     @Autowired
     private RedisService redisService;
 
@@ -38,13 +40,14 @@
 
     private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY;
 
+    private final static String ACCESS_TOKEN_STUDY = CacheConstants.LOGIN_TOKEN_KEY_STUDY;
+
     private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE;
 
     /**
      * 创建令牌
      */
-    public Map<String, Object> createToken(LoginUser loginUser)
-    {
+    public Map<String, Object> createToken(LoginUser loginUser) {
         String token = IdUtils.fastUUID();
         Long userId = loginUser.getSysUser().getUserId();
         String userName = loginUser.getSysUser().getUserName();
@@ -66,8 +69,8 @@
         rspMap.put("expires_in", expireTime);
         return rspMap;
     }
-    public Map<String, Object> createToken1(LoginUserParent loginUser)
-    {
+
+    public Map<String, Object> createToken1(LoginUserParent loginUser) {
         String token = IdUtils.fastUUID();
         Integer userId = loginUser.getUserid();
         String name = loginUser.getName();
@@ -85,13 +88,32 @@
         rspMap.put("expires_in", expireTime);
         return rspMap;
     }
+
+    public Map<String, Object> createTokenStudy(LoginUserParent loginUser) {
+        String token = IdUtils.fastUUID();
+        Integer userId = loginUser.getUserid();
+        String name = loginUser.getName();
+        loginUser.setToken(token);
+        loginUser.setIpaddr(IpUtils.getIpAddr());
+        refreshTokenStudy(loginUser);
+        // Jwt存储信息
+        Map<String, Object> claimsMap = new HashMap<String, Object>(8);
+        claimsMap.put(SecurityConstants.USER_STUDY_KEY, token);
+        claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId);
+        claimsMap.put(SecurityConstants.DETAILS_USERNAME, name);
+        // 接口返回信息
+        Map<String, Object> rspMap = new HashMap<String, Object>();
+        rspMap.put("access_token", JwtUtils.createToken(claimsMap));
+        rspMap.put("expires_in", expireTime);
+        return rspMap;
+    }
+
     /**
      * 获取用户身份信息
      *
      * @return 用户信息
      */
-    public LoginUser getLoginUser()
-    {
+    public LoginUser getLoginUser() {
         return getLoginUser(ServletUtils.getRequest());
     }
 
@@ -100,20 +122,32 @@
      *
      * @return 用户信息
      */
-    public LoginUser getLoginUser(HttpServletRequest request)
-    {
+    public LoginUser getLoginUser(HttpServletRequest request) {
         // 获取请求携带的令牌
         String token = SecurityUtils.getToken(request);
         return getLoginUser(token);
     }
+
     /**
      * 家长端/学习端获取用户身份信息
      *
      * @return 用户信息
      */
-    public LoginUserParent getLoginUser1()
-    {
+    public LoginUserParent getLoginUser1() {
         return getLoginUser1(ServletUtils.getRequest());
+    }
+
+    /**
+     * 学习端获取用户身份信息
+     *
+     * @return 用户信息
+     */
+    public LoginUserParent getLoginUserStudy() {
+        LoginUserParent userStudy = getLoginUserStudy(ServletUtils.getRequest());
+        if (null == userStudy) {
+            throw new StudyLoginException("登录失效,请重新登录!", 504);
+        }
+        return userStudy;
     }
 
     /**
@@ -121,55 +155,83 @@
      *
      * @return 用户信息
      */
-    public LoginUserParent getLoginUser1(HttpServletRequest request)
-    {
+    public LoginUserParent getLoginUser1(HttpServletRequest request) {
         // 获取请求携带的令牌
         String token = SecurityUtils.getToken(request);
         return getLoginUser1(token);
     }
 
     /**
+     * 学习端获取用户身份信息
+     *
+     * @return 用户信息
+     */
+    public LoginUserParent getLoginUserStudy(HttpServletRequest request) {
+        // 获取请求携带的令牌
+        String token = SecurityUtils.getToken(request);
+        return getLoginUserStudy(token);
+    }
+
+    /**
      * 获取用户身份信息
      *
      * @return 用户信息
      */
-    public LoginUser getLoginUser(String token)
-    {
+    public LoginUser getLoginUser(String token) {
         LoginUser user = null;
-        try
-        {
-            if (StringUtils.isNotEmpty(token))
-            {
+        try {
+            if (StringUtils.isNotEmpty(token)) {
                 String userkey = JwtUtils.getUserKey(token);
                 user = redisService.getCacheObject(getTokenKey(userkey));
                 return user;
             }
-        }
-        catch (Exception e)
-        {
+        } catch (Exception e) {
         }
         return user;
     }
+
     /**
      * 家长端 学习端 获取用户身份信息
      *
      * @return 用户信息
      */
-    public LoginUserParent getLoginUser1(String token)
-    {
+    public LoginUserParent getLoginUser1(String token) {
         LoginUserParent user = null;
-        try
-        {
-            if (StringUtils.isNotEmpty(token))
-            {
+        try {
+            if (StringUtils.isNotEmpty(token)) {
                 String userkey = JwtUtils.getUserKey1(token);
                 user = redisService.getCacheObject(getTokenKey(userkey));
                 return user;
             }
-        }
-        catch (Exception e)
-        {
+        } catch (Exception e) {
             e.printStackTrace();
+        }
+        return user;
+    }
+
+    /**
+     * 学习端 获取用户身份信息
+     *
+     * @return 用户信息
+     */
+    public LoginUserParent getLoginUserStudy(String token) {
+        LoginUserParent user = null;
+        if (StringUtils.isNotEmpty(token)) {
+            String userkey = JwtUtils.getUserKeyStudy(token);
+            user = redisService.getCacheObject(getTokenKeyStudy(userkey));
+            // 再次判断登录状态是否已过期
+            if (null == user) {
+                throw new StudyLoginException("登录信息已过期,请重新登录!", 504);
+            }
+            // 优先判断当前账号是否已在其他设备登录
+            if (!user.getIsCanLogin()) {
+                throw new StudyLoginException("当前登录账号在其他设备登录!", 505);
+            }
+            // 再次判断登录状态是否已过期
+            if (System.currentTimeMillis() > user.getExpireTime()) {
+                throw new StudyLoginException("登录信息已过期,请重新登录!", 504);
+            }
+            return user;
         }
         return user;
     }
@@ -177,10 +239,8 @@
     /**
      * 设置用户身份信息
      */
-    public void setLoginUser(LoginUser loginUser)
-    {
-        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
-        {
+    public void setLoginUser(LoginUser loginUser) {
+        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) {
             refreshToken(loginUser);
         }
     }
@@ -188,23 +248,30 @@
     /**
      * 删除用户缓存信息
      */
-    public void delLoginUser(String token)
-    {
-        if (StringUtils.isNotEmpty(token))
-        {
+    public void delLoginUser(String token) {
+        if (StringUtils.isNotEmpty(token)) {
             String userkey = JwtUtils.getUserKey(token);
             redisService.deleteObject(getTokenKey(userkey));
         }
     }
+
     /**
      * 家长端删除用户缓存信息
      */
-    public void delLoginUser1(String token)
-    {
-        if (StringUtils.isNotEmpty(token))
-        {
+    public void delLoginUser1(String token) {
+        if (StringUtils.isNotEmpty(token)) {
             String userkey = JwtUtils.getUserKey1(token);
             redisService.deleteObject(getTokenKey(userkey));
+        }
+    }
+
+    /**
+     * 学习端删除用户缓存信息
+     */
+    public void delLoginUserStudy(String token) {
+        if (StringUtils.isNotEmpty(token)) {
+            String userkey = JwtUtils.getUserKeyStudy(token);
+            redisService.deleteObject(getTokenKeyStudy(userkey));
         }
     }
 
@@ -213,13 +280,35 @@
      *
      * @param loginUser
      */
-    public void verifyToken(LoginUser loginUser)
-    {
+    public void verifyToken(LoginUser loginUser) {
         long expireTime = loginUser.getExpireTime();
         long currentTime = System.currentTimeMillis();
-        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
-        {
+        if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
             refreshToken(loginUser);
+        }
+    }
+
+    /**
+     * 验证令牌有效期,相差不足120分钟,自动刷新缓存
+     *
+     * @param loginUser
+     */
+    public void verifyToken1(LoginUserParent loginUser) {
+        long expireTime = loginUser.getExpireTime();
+        long currentTime = System.currentTimeMillis();
+        if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
+            refreshToken1(loginUser);
+        }
+    }
+
+    /**
+     * 验证令牌有效期,相差不足120分钟,自动刷新缓存
+     */
+    public void verifyTokenStudy(LoginUserParent loginUser) {
+        long expireTime = loginUser.getExpireTime();
+        long currentTime = System.currentTimeMillis();
+        if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
+            refreshTokenStudy(loginUser);
         }
     }
 
@@ -228,8 +317,7 @@
      *
      * @param loginUser 登录信息
      */
-    public void refreshToken(LoginUser loginUser)
-    {
+    public void refreshToken(LoginUser loginUser) {
         loginUser.setLoginTime(System.currentTimeMillis());
         loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
         // 根据uuid将loginUser缓存
@@ -240,8 +328,7 @@
     /**
      * 家长端用户登录
      */
-    public void refreshToken1(LoginUserParent dto)
-    {
+    public void refreshToken1(LoginUserParent dto) {
         dto.setLoginTime(System.currentTimeMillis());
         dto.setExpireTime(dto.getLoginTime() + expireTime * MILLIS_MINUTE);
         // 根据uuid将loginUser缓存
@@ -249,8 +336,42 @@
         redisService.setCacheObject(userKey, dto, expireTime, TimeUnit.MINUTES);
     }
 
-    private String getTokenKey(String token)
-    {
+    /**
+     * 学习端用户登录
+     */
+    public void refreshTokenStudy(LoginUserParent dto) {
+        // 获取所有 login_tokens_study: 前缀的登录缓存
+        Set redisCache = redisService.getKeysPrefix(ACCESS_TOKEN_STUDY);
+        for (Object key : redisCache) {
+            String strKey = String.valueOf(key);
+            // 根据 login_tokens:加密token 获取用户登录信息
+            Object redisCacheUserInfo = redisService.getCacheObject(strKey);
+            LoginUserParent redisUserInfo = JSONObject.parseObject(JSONObject.toJSONString(redisCacheUserInfo), LoginUserParent.class);
+            // 单点逻辑,如果当前用户已处于登录状态并再次登录,则清除该用户上一次登录token
+            if (dto.getUserid().equals(redisUserInfo.getUserid())) {
+                // 被挤账户 可登录状态 已经为 false时,跳出循环
+                if (!redisUserInfo.getIsCanLogin()) {
+                    continue;
+                }
+                // 设置能否登录字段为 否,当该token登录时,isCanLogin为false表示账号被挤
+                redisUserInfo.setIsCanLogin(Boolean.FALSE);
+                redisService.setCacheObject(strKey, redisUserInfo, redisService.getExpire(strKey), TimeUnit.SECONDS);
+            }
+        }
+        // 单点登录逻辑
+        dto.setLoginTime(System.currentTimeMillis());
+        dto.setExpireTime(dto.getLoginTime() + expireTime * MILLIS_MINUTE);
+        // 根据uuid将loginUser缓存
+        String userKey = getTokenKeyStudy(dto.getToken());
+        redisService.setCacheObject(userKey, dto, expireTime, TimeUnit.MINUTES);
+    }
+
+    private String getTokenKey(String token) {
         return ACCESS_TOKEN + token;
     }
+
+    private String getTokenKeyStudy(String token) {
+        return ACCESS_TOKEN_STUDY + token;
+    }
+
 }
\ No newline at end of file

--
Gitblit v1.7.1