diff --git a/src/main/java/com/youlai/boot/framework/security/exception/CaptchaValidationException.java b/src/main/java/com/youlai/boot/framework/security/exception/SmsCaptchaException.java
similarity index 56%
rename from src/main/java/com/youlai/boot/framework/security/exception/CaptchaValidationException.java
rename to src/main/java/com/youlai/boot/framework/security/exception/SmsCaptchaException.java
index b7c68cc4..8fca2cd9 100644
--- a/src/main/java/com/youlai/boot/framework/security/exception/CaptchaValidationException.java
+++ b/src/main/java/com/youlai/boot/framework/security/exception/SmsCaptchaException.java
@@ -3,13 +3,13 @@ package com.youlai.boot.framework.security.exception;
import org.springframework.security.core.AuthenticationException;
/**
- * 验证码校验异常
+ * 短信验证码异常
*
* @author Ray.Hao
* @since 2025/3/1
*/
-public class CaptchaValidationException extends AuthenticationException {
- public CaptchaValidationException(String msg) {
+public class SmsCaptchaException extends AuthenticationException {
+ public SmsCaptchaException(String msg) {
super(msg);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/youlai/boot/framework/security/exception/TokenInvalidException.java b/src/main/java/com/youlai/boot/framework/security/exception/TokenInvalidException.java
new file mode 100644
index 00000000..a4bb93c2
--- /dev/null
+++ b/src/main/java/com/youlai/boot/framework/security/exception/TokenInvalidException.java
@@ -0,0 +1,21 @@
+package com.youlai.boot.framework.security.exception;
+
+import com.youlai.boot.common.result.ResultCode;
+import lombok.Getter;
+
+/**
+ * Token 无效异常(access_token 或 refresh_token 过期/无效)
+ *
+ * @author Ray.Hao
+ * @since 4.3.1
+ */
+@Getter
+public class TokenInvalidException extends RuntimeException {
+
+ private final ResultCode resultCode;
+
+ public TokenInvalidException(ResultCode resultCode) {
+ super(resultCode.getMsg());
+ this.resultCode = resultCode;
+ }
+}
diff --git a/src/main/java/com/youlai/boot/framework/security/provider/SmsAuthenticationProvider.java b/src/main/java/com/youlai/boot/framework/security/provider/SmsAuthenticationProvider.java
index ec5c63f1..3450bd7a 100644
--- a/src/main/java/com/youlai/boot/framework/security/provider/SmsAuthenticationProvider.java
+++ b/src/main/java/com/youlai/boot/framework/security/provider/SmsAuthenticationProvider.java
@@ -3,7 +3,7 @@ package com.youlai.boot.framework.security.provider;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.youlai.boot.common.constant.RedisConstants;
-import com.youlai.boot.framework.security.exception.CaptchaValidationException;
+import com.youlai.boot.framework.security.exception.SmsCaptchaException;
import com.youlai.boot.framework.security.model.SmsAuthenticationToken;
import com.youlai.boot.framework.security.model.SysUserDetails;
import com.youlai.boot.framework.security.model.UserAuthInfo;
@@ -62,11 +62,11 @@ public class SmsAuthenticationProvider implements AuthenticationProvider {
// 参数校验
if (StrUtil.isBlank(mobile)) {
log.warn("短信验证码登录失败:手机号为空");
- throw new CaptchaValidationException("手机号不能为空");
+ throw new SmsCaptchaException("手机号不能为空");
}
if (StrUtil.isBlank(inputVerifyCode)) {
log.warn("短信验证码登录失败:验证码为空,手机号={}", mobile);
- throw new CaptchaValidationException("验证码不能为空");
+ throw new SmsCaptchaException("验证码不能为空");
}
// 根据手机号获取用户信息
@@ -89,12 +89,12 @@ public class SmsAuthenticationProvider implements AuthenticationProvider {
if (cachedVerifyCode == null) {
log.warn("短信验证码登录失败:验证码已过期,手机号={}", mobile);
- throw new CaptchaValidationException("验证码已过期,请重新获取");
+ throw new SmsCaptchaException("验证码已过期,请重新获取");
}
if (!StrUtil.equals(inputVerifyCode, cachedVerifyCode)) {
log.warn("短信验证码登录失败:验证码错误,手机号={}", mobile);
- throw new CaptchaValidationException("验证码错误");
+ throw new SmsCaptchaException("验证码错误");
}
// 验证成功后删除验证码,防止重复使用
diff --git a/src/main/java/com/youlai/boot/framework/security/token/JwtTokenManager.java b/src/main/java/com/youlai/boot/framework/security/token/JwtTokenManager.java
index 10966bd5..1b153f64 100644
--- a/src/main/java/com/youlai/boot/framework/security/token/JwtTokenManager.java
+++ b/src/main/java/com/youlai/boot/framework/security/token/JwtTokenManager.java
@@ -12,9 +12,9 @@ import cn.hutool.jwt.JWTUtil;
import com.youlai.boot.common.constant.JwtClaimConstants;
import com.youlai.boot.common.constant.RedisConstants;
import com.youlai.boot.common.constant.SecurityConstants;
-import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.common.result.ResultCode;
import com.youlai.boot.framework.security.config.SecurityProperties;
+import com.youlai.boot.framework.security.exception.TokenInvalidException;
import com.youlai.boot.framework.security.model.AuthenticationToken;
import com.youlai.boot.framework.security.model.RoleDataScope;
import org.apache.commons.lang3.StringUtils;
@@ -300,7 +300,7 @@ public class JwtTokenManager implements TokenManager {
public AuthenticationToken refreshToken(String refreshToken) {
boolean isValid = validateRefreshToken(refreshToken);
if (!isValid) {
- throw new BusinessException(ResultCode.REFRESH_TOKEN_INVALID);
+ throw new TokenInvalidException(ResultCode.REFRESH_TOKEN_INVALID);
}
Authentication authentication = parseToken(refreshToken);
int accessTokenExpiration = securityProperties.getSession().getAccessTokenTimeToLive();
diff --git a/src/main/java/com/youlai/boot/framework/security/token/RedisTokenManager.java b/src/main/java/com/youlai/boot/framework/security/token/RedisTokenManager.java
index 1616bbee..f58ab324 100644
--- a/src/main/java/com/youlai/boot/framework/security/token/RedisTokenManager.java
+++ b/src/main/java/com/youlai/boot/framework/security/token/RedisTokenManager.java
@@ -5,9 +5,9 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.youlai.boot.common.constant.RedisConstants;
import com.youlai.boot.common.constant.SecurityConstants;
-import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.common.result.ResultCode;
import com.youlai.boot.framework.security.config.SecurityProperties;
+import com.youlai.boot.framework.security.exception.TokenInvalidException;
import com.youlai.boot.framework.security.model.AuthenticationToken;
import com.youlai.boot.framework.security.model.UserSession;
import com.youlai.boot.framework.security.model.SysUserDetails;
@@ -147,7 +147,7 @@ public class RedisTokenManager implements TokenManager {
UserSession userSession = (UserSession) redisTemplate.opsForValue()
.get(StrUtil.format(RedisConstants.Auth.REFRESH_TOKEN_USER, refreshToken));
if (userSession == null) {
- throw new BusinessException(ResultCode.REFRESH_TOKEN_INVALID);
+ throw new TokenInvalidException(ResultCode.REFRESH_TOKEN_INVALID);
}
Object oldAccessTokenValue = redisTemplate.opsForValue().get(StrUtil.format(RedisConstants.Auth.USER_ACCESS_TOKEN, userSession.getUserId()));
// 删除旧的访问令牌记录
diff --git a/src/main/java/com/youlai/boot/framework/web/advice/GlobalExceptionHandler.java b/src/main/java/com/youlai/boot/framework/web/advice/GlobalExceptionHandler.java
index 7be6bbce..9b74c532 100644
--- a/src/main/java/com/youlai/boot/framework/web/advice/GlobalExceptionHandler.java
+++ b/src/main/java/com/youlai/boot/framework/web/advice/GlobalExceptionHandler.java
@@ -5,6 +5,7 @@ import tools.jackson.core.JacksonException;
import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.common.result.Result;
import com.youlai.boot.common.result.ResultCode;
+import com.youlai.boot.framework.security.exception.TokenInvalidException;
import jakarta.servlet.ServletException;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
@@ -222,6 +223,17 @@ public class GlobalExceptionHandler {
return Result.failed(ResultCode.INTEGRITY_CONSTRAINT_VIOLATION);
}
+ /**
+ * 处理 Token 无效异常
+ *
+ * 当 access_token 或 refresh_token 过期/无效时,返回 401。
+ */
+ @ExceptionHandler(TokenInvalidException.class)
+ @ResponseStatus(HttpStatus.UNAUTHORIZED)
+ public Result handleTokenInvalidException(TokenInvalidException e) {
+ return Result.failed(e.getResultCode());
+ }
+
/**
* 处理业务异常
*
diff --git a/src/main/resources/templates/codegen/backend/mapper.xml.vm b/src/main/resources/templates/codegen/backend/mapper.xml.vm
index 987b16a1..301bfe4a 100644
--- a/src/main/resources/templates/codegen/backend/mapper.xml.vm
+++ b/src/main/resources/templates/codegen/backend/mapper.xml.vm
@@ -27,7 +27,7 @@
#else
#end
- #set ($queryType = ${fieldConfig.queryType}.name())
+ #set ($queryType = $fieldConfig.queryType.name())
#if($queryType == "EQ")
AND ${fieldConfig.columnName} = #{queryParams.${fieldConfig.fieldName}}
#elseif($queryType == "LIKE")