feat(auth):重构认证登录接口返回结构
- 修改登录接口返回类型为 AuthTokenResponse - 新增 AuthTokenResponse DTO 类封装 token 和 tokenHead - 调整 AuthService 接口及实现类返回值类型 - 移除 Controller 层手动构造返回数据逻辑 - 完善异常处理逻辑,区分不同认证失败场景 - 新增用户未启用状态的错误码和处理 - 添加全局异常处理器对授权拒绝异常的处理
This commit is contained in:
@@ -21,6 +21,9 @@ public enum ErrorCode {
|
|||||||
PASSWORD_FORMAT_ERROR(400, "USER-104", "密码需6-20位字符组合"),
|
PASSWORD_FORMAT_ERROR(400, "USER-104", "密码需6-20位字符组合"),
|
||||||
USER_NOT_EXISTS(404, "USER-104", "用户不存在"),
|
USER_NOT_EXISTS(404, "USER-104", "用户不存在"),
|
||||||
USER_ID_INVALID(400, "USER-105", "用户ID无效"),
|
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_NOT_LOGIN(401, "USER-105", "请先登录"),
|
||||||
USER_BANNED(403, "USER-106", "账号已被封禁"),
|
USER_BANNED(403, "USER-106", "账号已被封禁"),
|
||||||
EMAIL_EXISTS(409, "USER-107", "邮箱已注册"),
|
EMAIL_EXISTS(409, "USER-107", "邮箱已注册"),
|
||||||
@@ -37,10 +40,11 @@ public enum ErrorCode {
|
|||||||
COMMENT_TOO_LONG(400, "POST-206", "评论超过500字限制"),
|
COMMENT_TOO_LONG(400, "POST-206", "评论超过500字限制"),
|
||||||
|
|
||||||
// ================== 系统/第三方 (300-399) ==================
|
// ================== 系统/第三方 (300-399) ==================
|
||||||
|
SYSTEM_ERROR(500, "SYS-300", "系统错误"),
|
||||||
CAPTCHA_ERROR(400, "SYS-301", "验证码错误"),
|
CAPTCHA_ERROR(400, "SYS-301", "验证码错误"),
|
||||||
SMS_SEND_FAILED(500, "SYS-302", "短信发送失败"),
|
SMS_SEND_FAILED(500, "SYS-302", "短信发送失败"),
|
||||||
FILE_UPLOAD_FAILED(500, "SYS-303", "文件上传失败"),
|
FILE_UPLOAD_FAILED(500, "SYS-303", "文件上传失败"),
|
||||||
RATE_LIMIT_EXCEEDED(429, "SYS-304", "操作过于频繁"), ;
|
RATE_LIMIT_EXCEEDED(429, "SYS-304", "操作过于频繁");
|
||||||
|
|
||||||
private final int httpStatus;
|
private final int httpStatus;
|
||||||
private final String code; // 业务错误码(领域-编号)
|
private final String code; // 业务错误码(领域-编号)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package cn.nopj.chaos_api.dto.response;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
|
||||||
|
public class AuthTokenResponse {
|
||||||
|
private String tokenHead;
|
||||||
|
private String token;
|
||||||
|
}
|
||||||
@@ -3,22 +3,19 @@ package cn.nopj.chaos_api.controller;
|
|||||||
import cn.nopj.chaos_api.converter.UserConverter;
|
import cn.nopj.chaos_api.converter.UserConverter;
|
||||||
import cn.nopj.chaos_api.dto.request.AuthLoginRequest;
|
import cn.nopj.chaos_api.dto.request.AuthLoginRequest;
|
||||||
import cn.nopj.chaos_api.dto.request.AuthRegisterRequest;
|
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.model.ApiResult;
|
||||||
import cn.nopj.chaos_api.service.AuthService;
|
import cn.nopj.chaos_api.service.AuthService;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证控管理
|
* 认证管理
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@@ -27,8 +24,7 @@ public class AuthController {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthService authService;
|
private AuthService authService;
|
||||||
@Value("${jwt.tokenHead}")
|
|
||||||
private String tokenHead;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserConverter userConverter;
|
private UserConverter userConverter;
|
||||||
@@ -49,15 +45,7 @@ public class AuthController {
|
|||||||
* @return 登录结果
|
* @return 登录结果
|
||||||
*/
|
*/
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ApiResult<?> login(@RequestBody AuthLoginRequest authLoginRequest) {
|
public ApiResult<AuthTokenResponse> login(@RequestBody AuthLoginRequest authLoginRequest) {
|
||||||
|
return ApiResult.success(authService.login(authLoginRequest.getUsername(), authLoginRequest.getPassword()));
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import cn.nopj.chaos_api.model.ApiResult;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.security.authorization.AuthorizationDeniedException;
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
@@ -40,4 +41,10 @@ public class GlobalExceptionHandler {
|
|||||||
log.error("服务器内部错误", ex);
|
log.error("服务器内部错误", ex);
|
||||||
return ApiResult.failed("服务器内部错误,请联系管理员");
|
return ApiResult.failed("服务器内部错误,请联系管理员");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(AuthorizationDeniedException.class)
|
||||||
|
public ApiResult<?> handleAuthorizationDeniedException(AuthorizationDeniedException ex) {
|
||||||
|
|
||||||
|
return ApiResult.failed("权限不足,请求已登记");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cn.nopj.chaos_api.service;
|
package cn.nopj.chaos_api.service;
|
||||||
|
|
||||||
import cn.nopj.chaos_api.domain.entity.User;
|
import cn.nopj.chaos_api.domain.entity.User;
|
||||||
|
import cn.nopj.chaos_api.dto.response.AuthTokenResponse;
|
||||||
|
|
||||||
public interface AuthService {
|
public interface AuthService {
|
||||||
/**
|
/**
|
||||||
@@ -12,5 +13,5 @@ public interface AuthService {
|
|||||||
* 登录
|
* 登录
|
||||||
* @return 生成的 JWT token
|
* @return 生成的 JWT token
|
||||||
*/
|
*/
|
||||||
String login(String username, String password);
|
AuthTokenResponse login(String username, String password);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.constants.ErrorCode;
|
||||||
import cn.nopj.chaos_api.common.exceotion.BizException;
|
import cn.nopj.chaos_api.common.exceotion.BizException;
|
||||||
import cn.nopj.chaos_api.domain.entity.User;
|
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.mapper.UserMapper;
|
||||||
import cn.nopj.chaos_api.service.AuthService;
|
import cn.nopj.chaos_api.service.AuthService;
|
||||||
import cn.nopj.chaos_api.util.JwtTokenUtil;
|
import cn.nopj.chaos_api.util.JwtTokenUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.authentication.DisabledException;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
@@ -30,7 +34,8 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
private JwtTokenUtil jwtTokenUtil;
|
private JwtTokenUtil jwtTokenUtil;
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
|
@Value("${jwt.tokenHead}")
|
||||||
|
private String tokenHead;
|
||||||
@Override
|
@Override
|
||||||
public User register(User user) {
|
public User register(User user) {
|
||||||
|
|
||||||
@@ -49,7 +54,7 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String login(String username, String password) {
|
public AuthTokenResponse login(String username, String password) {
|
||||||
// 尝试进行身份验证
|
// 尝试进行身份验证
|
||||||
try{
|
try{
|
||||||
Authentication authentication = authenticationManager.authenticate(
|
Authentication authentication = authenticationManager.authenticate(
|
||||||
@@ -57,20 +62,24 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 将认证结果保存在 SecurityContextHolder 中
|
// 将认证结果保存在 SecurityContextHolder 中
|
||||||
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
|
||||||
// 获取用户详情
|
// 获取用户详情
|
||||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||||
if (!userDetails.isEnabled()) {
|
if (!userDetails.isEnabled()) {
|
||||||
return null;
|
throw new BizException(ErrorCode.USER_NOT_ENABLED);
|
||||||
}
|
}
|
||||||
// 生成 JWT
|
AuthTokenResponse res = new AuthTokenResponse();
|
||||||
return jwtTokenUtil.generateToken(userDetails);
|
res.setToken(jwtTokenUtil.generateToken(userDetails));
|
||||||
|
res.setTokenHead(tokenHead);
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}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) {
|
} catch (Exception e) {
|
||||||
|
throw new BizException(ErrorCode.SYSTEM_ERROR);
|
||||||
throw new BizException(ErrorCode.USER_NOT_EXISTS);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user