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

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

Confidence: high
Scope-risk: narrow
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
“wuzhen”andCursor committed 2026-10-26 15:49:09 +08:00
1 parent a170cc6a48
commit 937cbb6bbd
1 file changed
+23 -12
@@ -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);
}