Explorar o código

sa-token改造

chendt %!s(int64=2) %!d(string=hai) anos
pai
achega
55f0a6b548

+ 10 - 30
mall4v/src/views/common/home.vue

@@ -24,14 +24,9 @@
         <tbody>
           <tr>
             <td>Spring Boot</td>
-            <td>2.1.6.RELEASE</td>
+            <td>3.0.4</td>
             <td>MVC核心框架</td>
           </tr>
-          <tr>
-            <td>Spring Security oauth2</td>
-            <td>2.1.5.RELEASE</td>
-            <td>认证和授权框架</td>
-          </tr>
           <tr>
             <td>MyBatis</td>
             <td>3.5.0</td>
@@ -39,22 +34,17 @@
           </tr>
           <tr>
             <td>MyBatisPlus</td>
-            <td>3.1.0</td>
+            <td>3.5.3.1</td>
             <td>基于mybatis,使用lambda表达式的</td>
           </tr>
           <tr>
             <td>Swagger-UI</td>
-            <td>2.9.2</td>
+            <td>4.0.0</td>
             <td>文档生产工具</td>
           </tr>
-          <tr>
-            <td>Hibernator-Validator</td>
-            <td>6.0.17.Final</td>
-            <td>验证框架</td>
-          </tr>
           <tr>
             <td>redisson</td>
-            <td>3.10.6</td>
+            <td>3.19.3</td>
             <td>对redis进行封装、集成分布式锁等</td>
           </tr>
           <tr>
@@ -64,19 +54,9 @@
           </tr>
           <tr>
             <td>log4j2</td>
-            <td>2.11.2</td>
+            <td>2.17.2</td>
             <td>更快的log日志工具</td>
           </tr>
-          <tr>
-            <td>fst</td>
-            <td>2.57</td>
-            <td>更快的序列化和反序列化工具</td>
-          </tr>
-          <tr>
-            <td>orika</td>
-            <td>1.5.4</td>
-            <td>更快的bean复制工具</td>
-          </tr>
           <tr>
             <td>lombok</td>
             <td>1.18.8</td>
@@ -84,13 +64,13 @@
           </tr>
           <tr>
             <td>hutool</td>
-            <td>4.5.0</td>
+            <td>5.8.15</td>
             <td>更适合国人的java工具集</td>
           </tr>
           <tr>
-            <td>swagger-bootstrap</td>
-            <td>1.9.3</td>
-            <td>基于swagger,更便于国人使用的swagger ui</td>
+            <td>xxl-job</td>
+            <td>2.3.1</td>
+            <td>定时任务</td>
           </tr>
         </tbody>
       </table>
@@ -112,7 +92,7 @@
         <tbody>
           <tr>
             <td>jdk</td>
-            <td>1.8+</td>
+            <td>17</td>
           </tr>
           <tr>
             <td>mysql</td>

+ 3 - 1
pom.xml

@@ -33,11 +33,13 @@
         <aliyun-dysmsapi.version>1.1.0</aliyun-dysmsapi.version>
         <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
         <redisson.version>3.19.3</redisson.version>
-        <transmittable-thread-local.version>2.12.1</transmittable-thread-local.version>
+        <transmittable-thread-local.version>2.14.2</transmittable-thread-local.version>
         <log4j.version>2.19.0</log4j.version>
         <knife4j.version>4.0.0</knife4j.version>
         <xxl-job.version>2.3.1</xxl-job.version>
         <spring-cloud-commons.version>4.0.1</spring-cloud-commons.version>
+        <satoken.version>1.34.0</satoken.version>
+        <fastjson.version>1.2.83</fastjson.version>
     </properties>
 
     <dependencyManagement>

+ 11 - 0
yami-shop-admin/src/main/resources/application.yml

@@ -25,3 +25,14 @@ mybatis-plus:
       field-strategy: NOT_NULL
       # 默认数据库表下划线命名
       table-underline: true
+sa-token:
+  # token名称 (同时也是cookie名称)
+  token-name: Authorization
+  # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
+  is-concurrent: true
+  # 在多人登录同一账号时,是否共用一个token(不共用,避免登出时导致其他用户也登出)
+  is-share: false
+  # token风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
+  token-style: uuid
+  # 是否输出操作日志
+  is-log: false

+ 11 - 0
yami-shop-api/src/main/resources/application.yml

@@ -29,3 +29,14 @@ mybatis-plus:
 management:
   server:
     add-application-context-header: false
+sa-token:
+  # token名称 (同时也是cookie名称)
+  token-name: Authorization
+  # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
+  is-concurrent: true
+  # 在多人登录同一账号时,是否共用一个token(不共用,避免登出时导致其他用户也登出)
+  is-share: false
+  # token风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
+  token-style: uuid
+  # 是否输出操作日志
+  is-log: false

+ 5 - 0
yami-shop-common/src/main/java/com/yami/shop/common/constants/OauthCacheNames.java

@@ -30,4 +30,9 @@ public interface OauthCacheNames {
      * 根据uid获取保存的token key缓存使用的key
      */
     String UID_TO_ACCESS = OAUTH_TOKEN_PREFIX + "uid_to_access:";
+
+    /**
+     * 保存token的用户信息使用的key
+     */
+    String USER_INFO = OAUTH_TOKEN_PREFIX + "user_info:";
 }

+ 1 - 1
yami-shop-common/src/main/java/com/yami/shop/common/response/ServerResponseEntity.java

@@ -106,7 +106,7 @@ public class ServerResponseEntity<T> implements Serializable {
 
     public ServerResponseEntity() {
         // 版本号
-        this.version = "mall4j.v230410";
+        this.version = "mall4j.v230424";
     }
 
     public static <T> ServerResponseEntity<T> success(T data) {

+ 17 - 0
yami-shop-security/yami-shop-security-common/pom.xml

@@ -28,6 +28,23 @@
             <artifactId>captcha</artifactId>
             <version>1.3.0</version>
         </dependency>
+        <!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-spring-boot3-starter</artifactId>
+            <version>${satoken.version}</version>
+        </dependency>
+        <!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-dao-redis-jackson</artifactId>
+            <version>${satoken.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>${fastjson.version}</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 13 - 1
yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/filter/AuthFilter.java

@@ -9,6 +9,7 @@
  */
 package com.yami.shop.security.common.filter;
 
+import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
 import com.yami.shop.common.exception.YamiShopBindException;
@@ -22,6 +23,7 @@ import com.yami.shop.security.common.util.AuthUserContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import org.springframework.util.AntPathMatcher;
 
@@ -51,6 +53,9 @@ public class AuthFilter implements Filter {
     @Autowired
     private TokenStore tokenStore;
 
+    @Value("${sa-token.token-name}")
+    private String tokenName;
+
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
             throws IOException, ServletException {
@@ -72,7 +77,7 @@ public class AuthFilter implements Filter {
             }
         }
 
-        String accessToken = req.getHeader("Authorization");
+        String accessToken = req.getHeader(tokenName);
         // 也许需要登录,不登陆也能用的uri
         boolean mayAuth = pathMatcher.match(AuthConfigAdapter.MAYBE_AUTH_URI, requestUri);
 
@@ -82,6 +87,13 @@ public class AuthFilter implements Filter {
         try {
             // 如果有token,就要获取token
             if (StrUtil.isNotBlank(accessToken)) {
+                // 校验登录,并从缓存中取出用户信息
+                try {
+                    StpUtil.checkLogin();
+                } catch (Exception e) {
+                    httpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED));
+                    return;
+                }
                 userInfoInToken = tokenStore.getUserInfoByAccessToken(accessToken, true);
             }
             else if (!mayAuth) {

+ 4 - 0
yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/PasswordManager.java

@@ -33,6 +33,10 @@ public class PasswordManager {
     public String passwordSignKey;
 
     public String decryptPassword(String data) {
+        // 在使用oracle的JDK时,JAR包必须签署特殊的证书才能使用。
+        // 解决方案 1.使用openJDK或者非oracle的JDK(建议) 2.添加证书
+        // hutool的aes报错可以打开下面那段代码
+        // SecureUtil.disableBouncyCastle();
         AES aes = new AES(passwordSignKey.getBytes(StandardCharsets.UTF_8));
         String decryptStr;
         String decryptPassword;

+ 82 - 224
yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/TokenStore.java

@@ -9,34 +9,26 @@
  */
 package com.yami.shop.security.common.manager;
 
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.BooleanUtil;
-import cn.hutool.core.util.IdUtil;
+import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.symmetric.AES;
+import com.alibaba.fastjson.JSON;
 import com.yami.shop.common.constants.OauthCacheNames;
-import com.yami.shop.common.response.ResponseEnum;
 import com.yami.shop.common.exception.YamiShopBindException;
-import com.yami.shop.common.util.PrincipalUtil;
+import com.yami.shop.common.response.ResponseEnum;
 import com.yami.shop.security.common.bo.TokenInfoBO;
 import com.yami.shop.security.common.bo.UserInfoInTokenBO;
 import com.yami.shop.security.common.enums.SysTypeEnum;
 import com.yami.shop.security.common.vo.TokenInfoVO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.data.redis.core.RedisCallback;
 import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
-import org.springframework.data.redis.serializer.RedisSerializer;
 import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
 
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 
 /**
  * token管理 1. 登陆返回token 2. 刷新token 3. 清除用户过去token 4. 校验token
@@ -49,96 +41,49 @@ public class TokenStore {
 
     private static final Logger logger = LoggerFactory.getLogger(TokenStore.class);
 
-    /**
-     * 用于aes签名的key,16位
-     */
-    @Value("${auth.token.signKey:-mall4j--mall4j-}")
-    public String tokenSignKey;
-
     private final RedisTemplate<String, Object> redisTemplate;
 
-    private final RedisSerializer<Object> redisSerializer;
-
-    private final StringRedisTemplate stringRedisTemplate;
-
-    public TokenStore(RedisTemplate<String, Object> redisTemplate,
-                      StringRedisTemplate stringRedisTemplate, GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer) {
+    public TokenStore(RedisTemplate<String, Object> redisTemplate) {
         this.redisTemplate = redisTemplate;
-        this.redisSerializer = genericJackson2JsonRedisSerializer;
-        this.stringRedisTemplate = stringRedisTemplate;
     }
 
-
     /**
-     * 将用户的部分信息存储在token中,并返回token信息
-     * @param userInfoInToken 用户在token中的信息
-     * @return token信息
+     * 以Sa-Token技术生成token,并返回token信息
+     * @param userInfoInToken
+     * @return
      */
-    public TokenInfoBO storeAccessToken(UserInfoInTokenBO userInfoInToken) {
+    public TokenInfoBO storeAccessSaToken(UserInfoInTokenBO userInfoInToken) {
+        // token生成
+        int timeoutSecond = getExpiresIn(userInfoInToken.getSysType());
+        String uid = this.getUid(userInfoInToken.getSysType().toString(), userInfoInToken.getUserId());
+        StpUtil.login(uid, timeoutSecond);
+        String token = StpUtil.getTokenValue();
+        // 用户信息存入缓存
+        String keyName = OauthCacheNames.USER_INFO + token;
+        redisTemplate.delete(keyName);
+        redisTemplate.opsForValue().set(
+                keyName,
+                JSON.toJSONString(userInfoInToken),
+                timeoutSecond,
+                TimeUnit.SECONDS
+        );
+        // 数据封装返回(token不用加密)
         TokenInfoBO tokenInfoBO = new TokenInfoBO();
-        String accessToken = IdUtil.simpleUUID();
-        String refreshToken = IdUtil.simpleUUID();
-
         tokenInfoBO.setUserInfoInToken(userInfoInToken);
-        tokenInfoBO.setExpiresIn(getExpiresIn(userInfoInToken.getSysType()));
-
-        String uidToAccessKeyStr = getUserIdToAccessKey(getApprovalKey(userInfoInToken));
-        String accessKeyStr = getAccessKey(accessToken);
-        String refreshToAccessKeyStr = getRefreshToAccessKey(refreshToken);
-
-        // 一个用户会登陆很多次,每次登陆的token都会存在 uid_to_access里面
-        // 但是每次保存都会更新这个key的时间,而key里面的token有可能会过期,过期就要移除掉
-        List<byte[]> existsAccessTokensBytes = new ArrayList<>();
-        // 新的token数据
-        existsAccessTokensBytes.add((accessToken + StrUtil.COLON + refreshToken).getBytes(StandardCharsets.UTF_8));
-
-        Long size = redisTemplate.opsForSet().size(uidToAccessKeyStr);
-        if (size != null && size != 0) {
-            List<String> tokenInfoBoList = stringRedisTemplate.opsForSet().pop(uidToAccessKeyStr, size);
-            if (tokenInfoBoList != null) {
-                for (String accessTokenWithRefreshToken : tokenInfoBoList) {
-                    String[] accessTokenWithRefreshTokenArr = accessTokenWithRefreshToken.split(StrUtil.COLON);
-                    String accessTokenData = accessTokenWithRefreshTokenArr[0];
-                    if (BooleanUtil.isTrue(stringRedisTemplate.hasKey(getAccessKey(accessTokenData)))) {
-                        existsAccessTokensBytes.add(accessTokenWithRefreshToken.getBytes(StandardCharsets.UTF_8));
-                    }
-                }
-            }
-        }
-
-        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
-
-            long expiresIn = tokenInfoBO.getExpiresIn();
-
-            byte[] uidKey = uidToAccessKeyStr.getBytes(StandardCharsets.UTF_8);
-            byte[] refreshKey = refreshToAccessKeyStr.getBytes(StandardCharsets.UTF_8);
-            byte[] accessKey = accessKeyStr.getBytes(StandardCharsets.UTF_8);
-
-            connection.sAdd(uidKey, ArrayUtil.toArray(existsAccessTokensBytes, byte[].class));
-
-            // 通过uid + sysType 保存access_token,当需要禁用用户的时候,可以根据uid + sysType 禁用用户
-            connection.expire(uidKey, expiresIn);
-
-            // 通过refresh_token获取用户的access_token从而刷新token
-            connection.setEx(refreshKey, expiresIn, accessToken.getBytes(StandardCharsets.UTF_8));
-
-            // 通过access_token保存用户的租户id,用户id,uid
-            connection.setEx(accessKey, expiresIn, Objects.requireNonNull(redisSerializer.serialize(userInfoInToken)));
-
-            return null;
-        });
-
-        // 返回给前端是加密的token
-        tokenInfoBO.setAccessToken(encryptToken(accessToken,userInfoInToken.getSysType()));
-        tokenInfoBO.setRefreshToken(encryptToken(refreshToken,userInfoInToken.getSysType()));
-
+        tokenInfoBO.setExpiresIn(timeoutSecond);
+        tokenInfoBO.setAccessToken(token);
+        tokenInfoBO.setRefreshToken(token);
         return tokenInfoBO;
     }
 
+    /**
+     * 计算过期时间(单位:秒)
+     * @param sysType
+     * @return
+     */
     private int getExpiresIn(int sysType) {
         // 3600秒
         int expiresIn = 3600;
-
         // 普通用户token过期时间 1小时
         if (Objects.equals(sysType, SysTypeEnum.ORDINARY.value())) {
             expiresIn = expiresIn * 24 * 30;
@@ -160,20 +105,12 @@ public class TokenStore {
         if (StrUtil.isBlank(accessToken)) {
             throw new YamiShopBindException(ResponseEnum.UNAUTHORIZED,"accessToken is blank");
         }
-        String realAccessToken;
-        if (needDecrypt) {
-            realAccessToken = decryptToken(accessToken);
-        }
-        else {
-            realAccessToken = accessToken;
+        String keyName = OauthCacheNames.USER_INFO + accessToken;
+        Object redisCache = redisTemplate.opsForValue().get(keyName);
+        if (redisCache == null) {
+            throw new YamiShopBindException(ResponseEnum.UNAUTHORIZED,"登录过期,请重新登录");
         }
-        UserInfoInTokenBO userInfoInTokenBO = (UserInfoInTokenBO) redisTemplate.opsForValue()
-                .get(getAccessKey(realAccessToken));
-
-        if (userInfoInTokenBO == null) {
-            throw new YamiShopBindException(ResponseEnum.UNAUTHORIZED,"accessToken 已过期");
-        }
-        return userInfoInTokenBO;
+        return JSON.parseObject(redisCache.toString(), UserInfoInTokenBO.class);
     }
 
     /**
@@ -185,106 +122,43 @@ public class TokenStore {
         if (StrUtil.isBlank(refreshToken)) {
             throw new YamiShopBindException(ResponseEnum.UNAUTHORIZED,"refreshToken is blank");
         }
-        String realRefreshToken = decryptToken(refreshToken);
-        String accessToken = stringRedisTemplate.opsForValue().get(getRefreshToAccessKey(realRefreshToken));
-
-        if (StrUtil.isBlank(accessToken)) {
-            throw new YamiShopBindException(ResponseEnum.UNAUTHORIZED,"refreshToken 已过期");
-        }
-        UserInfoInTokenBO userInfoInTokenBO = getUserInfoByAccessToken(accessToken,
-                false);
-
-        // 删除旧的refresh_token
-        stringRedisTemplate.delete(getRefreshToAccessKey(realRefreshToken));
-        // 删除旧的access_token
-        stringRedisTemplate.delete(getAccessKey(accessToken));
+        // 删除旧token
+        UserInfoInTokenBO userInfoInTokenBO = getUserInfoByAccessToken(refreshToken, false);
+        this.deleteCurrentToken(refreshToken);
         // 保存一份新的token
-        return storeAccessToken(userInfoInTokenBO);
+        return storeAccessSaToken(userInfoInTokenBO);
     }
 
     /**
-     * 删除全部的token
+     * 删除指定用户的全部的token
      */
     public void deleteAllToken(String sysType, String userId) {
-        String uidKey = getUserIdToAccessKey(getApprovalKey(sysType, userId));
-        Long size = redisTemplate.opsForSet().size(uidKey);
-        if (size == null || size == 0) {
-            return;
-        }
-        List<String> tokenInfoBoList = stringRedisTemplate.opsForSet().pop(uidKey, size);
-
-        if (CollUtil.isEmpty(tokenInfoBoList)) {
-            return;
-        }
-
-        for (String accessTokenWithRefreshToken : tokenInfoBoList) {
-            String[] accessTokenWithRefreshTokenArr = accessTokenWithRefreshToken.split(StrUtil.COLON);
-            String accessToken = accessTokenWithRefreshTokenArr[0];
-            String refreshToken = accessTokenWithRefreshTokenArr[1];
-            redisTemplate.delete(getRefreshToAccessKey(refreshToken));
-            redisTemplate.delete(getAccessKey(accessToken));
-        }
-        redisTemplate.delete(uidKey);
-
-    }
-
-    private static String getApprovalKey(UserInfoInTokenBO userInfoInToken) {
-        return getApprovalKey(userInfoInToken.getSysType().toString(), userInfoInToken.getUserId());
-    }
-
-    private static String getApprovalKey(String sysType, String userId) {
-        return userId == null?  sysType : sysType + StrUtil.COLON + userId;
-    }
-
-    private String encryptToken(String accessToken,Integer sysType) {
-        AES aes = new AES(tokenSignKey.getBytes(StandardCharsets.UTF_8));
-        return aes.encryptBase64(accessToken + System.currentTimeMillis() + sysType);
-    }
-
-    private String decryptToken(String data) {
-        AES aes = new AES(tokenSignKey.getBytes(StandardCharsets.UTF_8));
-        String decryptStr;
-        String decryptToken;
-        try {
-            decryptStr = aes.decryptStr(data);
-            decryptToken = decryptStr.substring(0,32);
-            // 创建token的时间,token使用时效性,防止攻击者通过一堆的尝试找到aes的密码,虽然aes是目前几乎最好的加密算法
-            long createTokenTime = Long.parseLong(decryptStr.substring(32,45));
-            // 系统类型
-            int sysType = Integer.parseInt(decryptStr.substring(45));
-            // token的过期时间
-            int expiresIn = getExpiresIn(sysType);
-            long second = 1000L;
-            if (System.currentTimeMillis() - createTokenTime > expiresIn * second) {
-                throw new YamiShopBindException(ResponseEnum.UNAUTHORIZED,"token error");
+        // 删除用户缓存
+        String uid = this.getUid(sysType, userId);
+        List<String> tokens = StpUtil.getTokenValueListByLoginId(uid);
+        if (!CollectionUtils.isEmpty(tokens)) {
+            List<String> keyNames = new ArrayList<>();
+            for (String token : tokens) {
+                keyNames.add(OauthCacheNames.USER_INFO + token);
             }
+            redisTemplate.delete(keyNames);
         }
-        catch (Exception e) {
-            throw new YamiShopBindException(ResponseEnum.UNAUTHORIZED,"token error");
-        }
-
-        // 防止解密后的token是脚本,从而对redis进行攻击,uuid只能是数字和小写字母
-        if (!PrincipalUtil.isSimpleChar(decryptToken)) {
-            throw new YamiShopBindException(ResponseEnum.UNAUTHORIZED,"token error");
-        }
-        return decryptToken;
-    }
-
-    public String getAccessKey(String accessToken) {
-        return OauthCacheNames.ACCESS + accessToken;
-    }
-
-    public String getUserIdToAccessKey(String approvalKey) {
-        return OauthCacheNames.UID_TO_ACCESS + approvalKey;
-    }
-
-    public String getRefreshToAccessKey(String refreshToken) {
-        return OauthCacheNames.REFRESH_TO_ACCESS + refreshToken;
+        // 移除token
+        StpUtil.logout(userId);
     }
 
+    /**
+     * 生成token,并返回token展示信息
+     * @param userInfoInToken
+     * @return
+     */
     public TokenInfoVO storeAndGetVo(UserInfoInTokenBO userInfoInToken) {
-        TokenInfoBO tokenInfoBO = storeAccessToken(userInfoInToken);
-
+        if (!userInfoInToken.getEnabled()){
+            // 用户已禁用,请联系客服
+            throw new YamiShopBindException("yami.user.disabled");
+        }
+        TokenInfoBO tokenInfoBO = storeAccessSaToken(userInfoInToken);
+        // 数据封装返回
         TokenInfoVO tokenInfoVO = new TokenInfoVO();
         tokenInfoVO.setAccessToken(tokenInfoBO.getAccessToken());
         tokenInfoVO.setRefreshToken(tokenInfoBO.getRefreshToken());
@@ -292,41 +166,25 @@ public class TokenStore {
         return tokenInfoVO;
     }
 
+    /**
+     * 删除当前登录的token
+     * @param accessToken 令牌
+     */
     public void deleteCurrentToken(String accessToken) {
-        String decryptToken = decryptToken(accessToken);
-
-        UserInfoInTokenBO userInfoInToken = getUserInfoByAccessToken(accessToken, true);
-
-        String uidKey = getUserIdToAccessKey(getApprovalKey(userInfoInToken.getSysType().toString(), userInfoInToken.getUserId()));
-        Long size = redisTemplate.opsForSet().size(uidKey);
-        if (size == null || size == 0) {
-            return;
-        }
-        List<String> tokenInfoBoList = stringRedisTemplate.opsForSet().pop(uidKey, size);
-
-        if (CollUtil.isEmpty(tokenInfoBoList)) {
-            return;
-        }
-        String dbAccessToken = null;
-        String dbRefreshToken = null;
-        List<byte[]> list = new ArrayList<>();
-        for (String accessTokenWithRefreshToken : tokenInfoBoList) {
-            String[] accessTokenWithRefreshTokenArr = accessTokenWithRefreshToken.split(StrUtil.COLON);
-            dbAccessToken = accessTokenWithRefreshTokenArr[0];
-            if (decryptToken.equals(dbAccessToken)) {
-                dbRefreshToken = accessTokenWithRefreshTokenArr[1];
-                redisTemplate.delete(getRefreshToAccessKey(dbRefreshToken));
-                redisTemplate.delete(getAccessKey(dbAccessToken));
-                continue;
-            }
-            list.add(accessTokenWithRefreshToken.getBytes(StandardCharsets.UTF_8));
-        }
+        // 删除用户缓存
+        String keyName = OauthCacheNames.USER_INFO + accessToken;
+        redisTemplate.delete(keyName);
+        // 移除token
+        StpUtil.logoutByTokenValue(accessToken);
+    }
 
-        if (CollUtil.isNotEmpty(list)) {
-            redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
-                connection.sAdd(uidKey.getBytes(StandardCharsets.UTF_8), ArrayUtil.toArray(list, byte[].class));
-                return null;
-            });
-        }
+    /**
+     * 生成各系统唯一uid
+     * @param sysType 系统类型
+     * @param userId 用户id
+     * @return
+     */
+    private String getUid(String sysType, String userId) {
+        return sysType + ":" + userId;
     }
 }