feat(auth):重构认证登录接口返回结构

- 修改登录接口返回类型为 AuthTokenResponse
- 新增 AuthTokenResponse DTO 类封装 token 和 tokenHead
- 调整 AuthService 接口及实现类返回值类型
- 移除 Controller 层手动构造返回数据逻辑
- 完善异常处理逻辑,区分不同认证失败场景
- 新增用户未启用状态的错误码和处理
- 添加全局异常处理器对授权拒绝异常的处理
This commit is contained in:
Chaos
2025-11-18 17:18:09 +08:00
parent 0527602d1c
commit 7e754b19d4
6 changed files with 47 additions and 28 deletions

View File

@@ -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; // 业务错误码(领域-编号)

View File

@@ -0,0 +1,10 @@
package cn.nopj.chaos_api.dto.response;
import lombok.Data;
@Data
public class AuthTokenResponse {
private String tokenHead;
private String token;
}

View File

@@ -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<String, String> tokenMap = new HashMap<>();
tokenMap.put("token", token);
tokenMap.put("tokenHead", tokenHead);
return ApiResult.success(tokenMap);
public ApiResult<AuthTokenResponse> login(@RequestBody AuthLoginRequest authLoginRequest) {
return ApiResult.success(authService.login(authLoginRequest.getUsername(), authLoginRequest.getPassword()));
}
}

View File

@@ -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("权限不足,请求已登记");
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}