Преглед изворни кода

fix(security): 登录清理旧会话时容忍 JWT 解析失败,避免无法登录

logoutByMaxLoginCount 会回调 doLogout,旧随机密钥签发的 token 导致 getExtra 抛异常并打断整个登录。

Confidence: high
Scope-risk: narrow
Co-authored-by: Cursor <cursoragent@cursor.com>
“wuzhen” пре 4 дана
родитељ
комит
937cbb6bbd

+ 23 - 12
backend/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java

@@ -76,15 +76,32 @@ public class UserActionListener implements SaTokenListener {
         log.info("user doLogin, userId:{}", loginId);
     }
 
+    /**
+     * 清理在线用户缓存。JWT 密钥变更后旧 token 无法 getExtra,绝不能抛异常打断登录流程
+     * (登录时 logoutByMaxLoginCount 会回调 doLogout/doReplaced)。
+     */
+    private void clearOnlineCache(Object loginId, String tokenValue) {
+        try {
+            String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+            TenantHelper.dynamic(tenantId, () ->
+                RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue));
+        } catch (Exception e) {
+            log.warn("清理在线缓存时 token 无法解析(多为 JWT 密钥变更后的旧会话), userId={}, err={}",
+                loginId, e.getMessage());
+            try {
+                RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+            } catch (Exception ignored) {
+                // ignore
+            }
+        }
+    }
+
     /**
      * 每次注销时触发
      */
     @Override
     public void doLogout(String loginType, Object loginId, String tokenValue) {
-        String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
-        TenantHelper.dynamic(tenantId, () -> {
-            RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
-        });
+        clearOnlineCache(loginId, tokenValue);
         log.info("user doLogout, userId:{}", loginId);
     }
 
@@ -93,10 +110,7 @@ public class UserActionListener implements SaTokenListener {
      */
     @Override
     public void doKickout(String loginType, Object loginId, String tokenValue) {
-        String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
-        TenantHelper.dynamic(tenantId, () -> {
-            RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
-        });
+        clearOnlineCache(loginId, tokenValue);
         log.info("user doKickout, userId:{}", loginId);
     }
 
@@ -105,10 +119,7 @@ public class UserActionListener implements SaTokenListener {
      */
     @Override
     public void doReplaced(String loginType, Object loginId, String tokenValue) {
-        String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
-        TenantHelper.dynamic(tenantId, () -> {
-            RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
-        });
+        clearOnlineCache(loginId, tokenValue);
         log.info("user doReplaced, userId:{}", loginId);
     }