diff --git a/backend/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java b/backend/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java index ba1e88d4..deca6db2 100644 --- a/backend/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java +++ b/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); }