diff --git a/daxpay-platform/daxpay-platform-capability/capability-auth/src/main/java/cn/daxpay/open/platform/capability/auth/handler/SaExceptionHandler.java b/daxpay-platform/daxpay-platform-capability/capability-auth/src/main/java/cn/daxpay/open/platform/capability/auth/handler/SaExceptionHandler.java index f269d036c..a19af5a68 100644 --- a/daxpay-platform/daxpay-platform-capability/capability-auth/src/main/java/cn/daxpay/open/platform/capability/auth/handler/SaExceptionHandler.java +++ b/daxpay-platform/daxpay-platform-capability/capability-auth/src/main/java/cn/daxpay/open/platform/capability/auth/handler/SaExceptionHandler.java @@ -2,6 +2,7 @@ package cn.daxpay.open.platform.capability.auth.handler; import cn.daxpay.open.platform.common.i18n.util.I18nUtil; import cn.daxpay.open.platform.core.code.CommonCode; +import cn.daxpay.open.platform.core.code.CommonErrorCode; import cn.daxpay.open.platform.core.rest.Res; import cn.daxpay.open.platform.core.rest.result.Result; import cn.daxpay.open.platform.capability.auth.exception.NotLoginException; @@ -37,6 +38,31 @@ public class SaExceptionHandler { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result); } + /// 处理 Sa-Token 抛出的未登录异常(被踢下线/顶下线/过期等) + /// + /// Sa-Token 自身的 [cn.dev33.satoken.exception.NotLoginException] 与本项目自定义的 + /// [NotLoginException] 同名但不同包, 互无继承关系; 前者继承自 [SaTokenException], + /// 若不在此单独处理, 会落入下方 [SaTokenException] 兜底而返回 500, 前端 401 拦截无法感知。 + /// 按异常 type 映射不同 i18n 文案, 返回 401 以便前端识别并跳转登录页。 + @ExceptionHandler(cn.dev33.satoken.exception.NotLoginException.class) + public ResponseEntity> handleSaTokenNotLoginException(cn.dev33.satoken.exception.NotLoginException ex) { + String type = ex.getType(); + // 按未登录原因映射 i18n 消息 key + String messageKey = switch (type) { + case cn.dev33.satoken.exception.NotLoginException.NOT_TOKEN -> "error.auth.notToken"; + case cn.dev33.satoken.exception.NotLoginException.INVALID_TOKEN -> "error.auth.invalidToken"; + case cn.dev33.satoken.exception.NotLoginException.TOKEN_TIMEOUT -> "error.auth.tokenTimeout"; + case cn.dev33.satoken.exception.NotLoginException.BE_REPLACED -> "error.auth.beReplaced"; + case cn.dev33.satoken.exception.NotLoginException.KICK_OUT -> "error.auth.kickOut"; + case cn.dev33.satoken.exception.NotLoginException.TOKEN_FREEZE -> "error.auth.tokenFreeze"; + default -> "error.auth.notLogin"; + }; + String message = I18nUtil.get(messageKey); + log.info("Sa-Token 未登录 type={}, key={}", type, messageKey); + Result result = Res.response(CommonErrorCode.AUTHENTICATION_FAIL, message, MDC.get(CommonCode.TRACE_ID)); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result); + } + /// 路径无权访问 @ExceptionHandler(RouterCheckException.class) public ResponseEntity> handleBusinessException(RouterCheckException ex) { diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/error/auth.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/error/auth.json index 5cc983c93..82a6dd2d9 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/error/auth.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/error/auth.json @@ -20,5 +20,11 @@ "twoFactorRequired": "Two-factor authentication required", "twoFactorCodeError": "Incorrect verification code or backup code", "twoFactorPreAuthExpired": "Pre-auth token is invalid or expired, please log in again", - "loginRetryLock": "Too many failed login attempts, please try again in {0} minutes" + "loginRetryLock": "Too many failed login attempts, please try again in {0} minutes", + "notToken": "No authentication credential provided", + "invalidToken": "Invalid authentication credential", + "tokenTimeout": "Session expired, please log in again", + "beReplaced": "Account signed in on another device", + "kickOut": "Session no longer valid, please log in again", + "tokenFreeze": "Authentication credential frozen" } diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/error/auth.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/error/auth.json index 648e62812..0d57f1355 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/error/auth.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/error/auth.json @@ -20,5 +20,11 @@ "twoFactorRequired": "需要双因素认证", "twoFactorCodeError": "动态码或备用码错误", "twoFactorPreAuthExpired": "预认证令牌无效或已过期,请重新登录", - "loginRetryLock": "登录失败次数过多,请{0}分钟后重试" + "loginRetryLock": "登录失败次数过多,请{0}分钟后重试", + "notToken": "未提供登录凭证", + "invalidToken": "登录凭证无效", + "tokenTimeout": "登录已过期,请重新登录", + "beReplaced": "账号已在其他设备登录", + "kickOut": "登录状态已失效,请重新登录", + "tokenFreeze": "登录凭证已被冻结" }