From 7e754b19d494d6980a6e81b84f947cf8b6b3841a Mon Sep 17 00:00:00 2001 From: Chaos Date: Tue, 18 Nov 2025 17:18:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(auth):=E9=87=8D=E6=9E=84=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9E=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改登录接口返回类型为 AuthTokenResponse - 新增 AuthTokenResponse DTO 类封装 token 和 tokenHead - 调整 AuthService 接口及实现类返回值类型 - 移除 Controller 层手动构造返回数据逻辑 - 完善异常处理逻辑,区分不同认证失败场景 - 新增用户未启用状态的错误码和处理 - 添加全局异常处理器对授权拒绝异常的处理 --- .../chaos_api/common/constants/ErrorCode.java | 6 ++++- .../dto/response/AuthTokenResponse.java | 10 +++++++ .../chaos_api/controller/AuthController.java | 22 ++++----------- .../exception/GlobalExceptionHandler.java | 7 +++++ .../nopj/chaos_api/service/AuthService.java | 3 ++- .../service/impl/AuthServiceImpl.java | 27 ++++++++++++------- 6 files changed, 47 insertions(+), 28 deletions(-) create mode 100644 chaos_api_domain/src/main/java/cn/nopj/chaos_api/dto/response/AuthTokenResponse.java diff --git a/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/constants/ErrorCode.java b/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/constants/ErrorCode.java index 1c2b0fd..fd2475d 100644 --- a/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/constants/ErrorCode.java +++ b/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/constants/ErrorCode.java @@ -21,6 +21,9 @@ public enum ErrorCode { PASSWORD_FORMAT_ERROR(400, "USER-104", "密码需6-20位字符组合"), USER_NOT_EXISTS(404, "USER-104", "用户不存在"), USER_ID_INVALID(400, "USER-105", "用户ID无效"), + + USER_NOT_EXISTS_OR_PASSWORD_WRONG(401, "USER-105", "用户名不存在或密码错误"), + USER_NOT_ENABLED(403, "USER-106", "用户未启用"), USER_NOT_LOGIN(401, "USER-105", "请先登录"), USER_BANNED(403, "USER-106", "账号已被封禁"), EMAIL_EXISTS(409, "USER-107", "邮箱已注册"), @@ -37,10 +40,11 @@ public enum ErrorCode { COMMENT_TOO_LONG(400, "POST-206", "评论超过500字限制"), // ================== 系统/第三方 (300-399) ================== + SYSTEM_ERROR(500, "SYS-300", "系统错误"), CAPTCHA_ERROR(400, "SYS-301", "验证码错误"), SMS_SEND_FAILED(500, "SYS-302", "短信发送失败"), FILE_UPLOAD_FAILED(500, "SYS-303", "文件上传失败"), - RATE_LIMIT_EXCEEDED(429, "SYS-304", "操作过于频繁"), ; + RATE_LIMIT_EXCEEDED(429, "SYS-304", "操作过于频繁"); private final int httpStatus; private final String code; // 业务错误码(领域-编号) diff --git a/chaos_api_domain/src/main/java/cn/nopj/chaos_api/dto/response/AuthTokenResponse.java b/chaos_api_domain/src/main/java/cn/nopj/chaos_api/dto/response/AuthTokenResponse.java new file mode 100644 index 0000000..b9d01b3 --- /dev/null +++ b/chaos_api_domain/src/main/java/cn/nopj/chaos_api/dto/response/AuthTokenResponse.java @@ -0,0 +1,10 @@ +package cn.nopj.chaos_api.dto.response; + +import lombok.Data; + +@Data + +public class AuthTokenResponse { + private String tokenHead; + private String token; +} diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/AuthController.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/AuthController.java index 83d6118..75faa7e 100644 --- a/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/AuthController.java +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/AuthController.java @@ -3,22 +3,19 @@ package cn.nopj.chaos_api.controller; import cn.nopj.chaos_api.converter.UserConverter; import cn.nopj.chaos_api.dto.request.AuthLoginRequest; import cn.nopj.chaos_api.dto.request.AuthRegisterRequest; +import cn.nopj.chaos_api.dto.response.AuthTokenResponse; import cn.nopj.chaos_api.model.ApiResult; import cn.nopj.chaos_api.service.AuthService; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; -import java.util.Map; - /** - * 认证控管理 + * 认证管理 * */ @RestController @@ -27,8 +24,7 @@ public class AuthController { @Autowired private AuthService authService; - @Value("${jwt.tokenHead}") - private String tokenHead; + @Autowired private UserConverter userConverter; @@ -49,15 +45,7 @@ public class AuthController { * @return 登录结果 */ @PostMapping("/login") - public ApiResult login(@RequestBody AuthLoginRequest authLoginRequest) { - - String token = authService.login(authLoginRequest.getUsername(), authLoginRequest.getPassword()); - - Map tokenMap = new HashMap<>(); - tokenMap.put("token", token); - tokenMap.put("tokenHead", tokenHead); - return ApiResult.success(tokenMap); - - + public ApiResult login(@RequestBody AuthLoginRequest authLoginRequest) { + return ApiResult.success(authService.login(authLoginRequest.getUsername(), authLoginRequest.getPassword())); } } diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/exception/GlobalExceptionHandler.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/exception/GlobalExceptionHandler.java index 085b00e..ba9ab95 100644 --- a/chaos_api_web/src/main/java/cn/nopj/chaos_api/exception/GlobalExceptionHandler.java +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/exception/GlobalExceptionHandler.java @@ -5,6 +5,7 @@ import cn.nopj.chaos_api.model.ApiResult; import lombok.extern.slf4j.Slf4j; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; +import org.springframework.security.authorization.AuthorizationDeniedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -40,4 +41,10 @@ public class GlobalExceptionHandler { log.error("服务器内部错误", ex); return ApiResult.failed("服务器内部错误,请联系管理员"); } + + @ExceptionHandler(AuthorizationDeniedException.class) + public ApiResult handleAuthorizationDeniedException(AuthorizationDeniedException ex) { + + return ApiResult.failed("权限不足,请求已登记"); + } } diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/AuthService.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/AuthService.java index 4f4119d..6021f2b 100644 --- a/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/AuthService.java +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/AuthService.java @@ -1,6 +1,7 @@ package cn.nopj.chaos_api.service; import cn.nopj.chaos_api.domain.entity.User; +import cn.nopj.chaos_api.dto.response.AuthTokenResponse; public interface AuthService { /** @@ -12,5 +13,5 @@ public interface AuthService { * 登录 * @return 生成的 JWT token */ - String login(String username, String password); + AuthTokenResponse login(String username, String password); } diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/impl/AuthServiceImpl.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/impl/AuthServiceImpl.java index d3e00b4..cdf9298 100644 --- a/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/impl/AuthServiceImpl.java +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/impl/AuthServiceImpl.java @@ -4,12 +4,16 @@ package cn.nopj.chaos_api.service.impl; import cn.nopj.chaos_api.common.constants.ErrorCode; import cn.nopj.chaos_api.common.exceotion.BizException; import cn.nopj.chaos_api.domain.entity.User; +import cn.nopj.chaos_api.dto.response.AuthTokenResponse; import cn.nopj.chaos_api.mapper.UserMapper; import cn.nopj.chaos_api.service.AuthService; import cn.nopj.chaos_api.util.JwtTokenUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -30,7 +34,8 @@ public class AuthServiceImpl implements AuthService { private JwtTokenUtil jwtTokenUtil; @Autowired private AuthenticationManager authenticationManager; - + @Value("${jwt.tokenHead}") + private String tokenHead; @Override public User register(User user) { @@ -49,7 +54,7 @@ public class AuthServiceImpl implements AuthService { } @Override - public String login(String username, String password) { + public AuthTokenResponse login(String username, String password) { // 尝试进行身份验证 try{ Authentication authentication = authenticationManager.authenticate( @@ -57,20 +62,24 @@ public class AuthServiceImpl implements AuthService { ); // 将认证结果保存在 SecurityContextHolder 中 - SecurityContextHolder.getContext().setAuthentication(authentication); // 获取用户详情 UserDetails userDetails = (UserDetails) authentication.getPrincipal(); if (!userDetails.isEnabled()) { - return null; + throw new BizException(ErrorCode.USER_NOT_ENABLED); } - // 生成 JWT - return jwtTokenUtil.generateToken(userDetails); - }catch (Exception e){ + AuthTokenResponse res = new AuthTokenResponse(); + res.setToken(jwtTokenUtil.generateToken(userDetails)); + res.setTokenHead(tokenHead); + return res; - throw new BizException(ErrorCode.USER_NOT_EXISTS); + }catch (BadCredentialsException e) { + throw new BizException(ErrorCode.USER_NOT_EXISTS_OR_PASSWORD_WRONG); + } catch (DisabledException e) { + throw new BizException(ErrorCode.USER_NOT_ENABLED); + } catch (Exception e) { + throw new BizException(ErrorCode.SYSTEM_ERROR); } - } } \ No newline at end of file