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

fix(security): JWT 签名失败按未登录处理,避免页面报未知异常

密钥切换后残留 token 会在 getExtra 抛 SaJwtException,现统一返回 401 引导重新登录。

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

+ 11 - 0
backend/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/handler/SaTokenExceptionHandler.java

@@ -3,6 +3,7 @@ package org.dromara.common.satoken.handler;
 import cn.dev33.satoken.exception.NotLoginException;
 import cn.dev33.satoken.exception.NotPermissionException;
 import cn.dev33.satoken.exception.NotRoleException;
+import cn.dev33.satoken.jwt.exception.SaJwtException;
 import cn.hutool.http.HttpStatus;
 import jakarta.servlet.http.HttpServletRequest;
 import lombok.extern.slf4j.Slf4j;
@@ -49,4 +50,14 @@ public class SaTokenExceptionHandler {
         return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源");
     }
 
+    /**
+     * JWT 签名无效/解析失败(常见于密钥变更后残留旧 token)
+     */
+    @ExceptionHandler(SaJwtException.class)
+    public R<Void> handleSaJwtException(SaJwtException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',JWT校验失败'{}',无法访问系统资源", requestURI, e.getMessage());
+        return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "登录状态已失效,请重新登录");
+    }
+
 }

+ 11 - 1
backend/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java

@@ -59,9 +59,19 @@ public class SecurityConfig implements WebMvcConfigurer {
                         StpUtil.checkLogin();
 
                         // 检查 header 与 param 里的 clientid 与 token 里的是否一致
+                        // jwt 密钥切换后旧 token 会在 getExtra 时抛 SaJwtException,转为未登录避免页面报“未知异常”
                         String headerCid = request.getHeader(LoginHelper.CLIENT_KEY);
                         String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
-                        String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
+                        Object clientIdExtra;
+                        try {
+                            clientIdExtra = StpUtil.getExtra(LoginHelper.CLIENT_KEY);
+                        } catch (Exception e) {
+                            throw NotLoginException.newInstance(StpUtil.getLoginType(),
+                                NotLoginException.INVALID_TOKEN,
+                                "token无效或已过期,请重新登录",
+                                StpUtil.getTokenValue());
+                        }
+                        String clientId = clientIdExtra == null ? null : clientIdExtra.toString();
                         if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
                             // token 无效
                             throw NotLoginException.newInstance(StpUtil.getLoginType(),