feat: 添加getUserInfo接口和修复相关bug
- 添加 /getUserInfo 接口,支持根据accessToken获取用户信息 - 修复 JWT subject 从 userAccount 改为 userId - 修复 Results.failure 方法使用 getErrorMessage() 而非 getMessage() - 移除 UserClient.getUserById 方法中的 public 修饰符 - 代码格式化:统一缩进和代码风格 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,6 @@ public interface UserClient {
|
||||
Result<UserAuthRespDTO> getUserByUserName(@RequestParam("userAccount") String userAccount);
|
||||
|
||||
@GetMapping("/inner/get-by-userid")
|
||||
public Result<UserAuthRespDTO> getUserById(@RequestParam("userId") String userId);
|
||||
Result<UserAuthRespDTO> getUserById(@RequestParam("userId") String userId);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.meowrain.aioj.backend.auth.controller;
|
||||
|
||||
import cn.meowrain.aioj.backend.auth.dto.req.UserLoginRequestDTO;
|
||||
import cn.meowrain.aioj.backend.auth.dto.resp.UserAuthRespDTO;
|
||||
import cn.meowrain.aioj.backend.auth.dto.resp.UserLoginResponseDTO;
|
||||
import cn.meowrain.aioj.backend.auth.oauth2.service.OAuth2SessionService;
|
||||
import cn.meowrain.aioj.backend.auth.service.AuthService;
|
||||
@@ -54,4 +55,16 @@ public class AuthController {
|
||||
return Results.success(isValid);
|
||||
}
|
||||
|
||||
@GetMapping("/getUserInfo")
|
||||
public Result<UserAuthRespDTO> getUserInfo(@RequestHeader(value = "Authorization", required = false) String authorization) {
|
||||
String token = null;
|
||||
if(authorization != null && authorization.startsWith("Bearer ")){
|
||||
token = authorization.substring(7);
|
||||
}
|
||||
if(token != null && sessionService.isTokenBlacklisted(token)) {
|
||||
return Results.success(null);
|
||||
}
|
||||
return Results.success(authService.getUserInfo(token));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package cn.meowrain.aioj.backend.auth.service;
|
||||
|
||||
import cn.meowrain.aioj.backend.auth.dto.req.UserLoginRequestDTO;
|
||||
import cn.meowrain.aioj.backend.auth.dto.resp.UserAuthRespDTO;
|
||||
import cn.meowrain.aioj.backend.auth.dto.resp.UserLoginResponseDTO;
|
||||
import cn.meowrain.aioj.backend.framework.core.web.Result;
|
||||
|
||||
public interface AuthService {
|
||||
|
||||
@@ -26,4 +28,11 @@ public interface AuthService {
|
||||
*/
|
||||
Boolean validateToken(String accessToken);
|
||||
|
||||
|
||||
/**
|
||||
* 根据accessToken获取用户信息
|
||||
* @param accessToken
|
||||
* @return {@link Result<UserAuthRespDTO>}
|
||||
*/
|
||||
UserAuthRespDTO getUserInfo(String accessToken);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import cn.meowrain.aioj.backend.auth.dto.resp.UserLoginResponseDTO;
|
||||
import cn.meowrain.aioj.backend.auth.service.AuthService;
|
||||
import cn.meowrain.aioj.backend.auth.utils.JwtUtil;
|
||||
import cn.meowrain.aioj.backend.framework.core.errorcode.ErrorCode;
|
||||
import cn.meowrain.aioj.backend.framework.core.exception.ClientException;
|
||||
import cn.meowrain.aioj.backend.framework.core.exception.ServiceException;
|
||||
import cn.meowrain.aioj.backend.framework.core.web.Result;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -27,145 +28,195 @@ import java.util.concurrent.TimeUnit;
|
||||
@Slf4j
|
||||
public class AuthServiceImpl implements AuthService {
|
||||
|
||||
private final JwtUtil jwtUtil;
|
||||
private final JwtUtil jwtUtil;
|
||||
|
||||
private final UserLoginRequestParamVerifyContext userLoginRequestParamVerifyContext;
|
||||
private final UserLoginRequestParamVerifyContext userLoginRequestParamVerifyContext;
|
||||
|
||||
private final UserClient userClient;
|
||||
private final UserClient userClient;
|
||||
|
||||
private final StringRedisTemplate stringRedisTemplate;
|
||||
private final StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
private final JwtPropertiesConfiguration jwtPropertiesConfiguration;
|
||||
private final JwtPropertiesConfiguration jwtPropertiesConfiguration;
|
||||
|
||||
@Override
|
||||
public UserLoginResponseDTO userLogin(UserLoginRequestDTO requestParam) {
|
||||
log.info("用户登录请求: userAccount={}", requestParam.getUserAccount());
|
||||
@Override
|
||||
public UserLoginResponseDTO userLogin(UserLoginRequestDTO requestParam) {
|
||||
log.info("用户登录请求: userAccount={}", requestParam.getUserAccount());
|
||||
|
||||
// 1.校验
|
||||
userLoginRequestParamVerifyContext.handler(ChainMarkEnums.USER_LOGIN_REQ_PARAM_VERIFY.getMarkName(),
|
||||
requestParam);
|
||||
// 1.校验
|
||||
userLoginRequestParamVerifyContext.handler(ChainMarkEnums.USER_LOGIN_REQ_PARAM_VERIFY.getMarkName(),
|
||||
requestParam);
|
||||
|
||||
// 如果调用user-service失败,那么就说明是系统内部错误
|
||||
log.info("正在调用user-service查询用户信息...");
|
||||
Result<UserAuthRespDTO> userResp = userClient.getUserByUserName(requestParam.getUserAccount());
|
||||
// 如果调用user-service失败,那么就说明是系统内部错误
|
||||
log.info("正在调用user-service查询用户信息...");
|
||||
Result<UserAuthRespDTO> userResp = userClient.getUserByUserName(requestParam.getUserAccount());
|
||||
|
||||
if (userResp.isFail()) {
|
||||
log.error("调用user-service返回失败:{}", userResp.getMessage());
|
||||
throw new ServiceException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
if (userResp.isFail()) {
|
||||
log.error("调用user-service返回失败:{}", userResp.getMessage());
|
||||
throw new ServiceException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
UserAuthRespDTO user = userResp.getData();
|
||||
if (user == null) {
|
||||
log.warn("用户不存在: {}", requestParam.getUserAccount());
|
||||
throw new ServiceException("用户不存在或密码错误", ErrorCode.NOT_LOGIN_ERROR);
|
||||
}
|
||||
UserAuthRespDTO user = userResp.getData();
|
||||
if (user == null) {
|
||||
log.warn("用户不存在: {}", requestParam.getUserAccount());
|
||||
throw new ServiceException("用户不存在或密码错误", ErrorCode.NOT_LOGIN_ERROR);
|
||||
}
|
||||
|
||||
if (!BCrypt.checkpw(requestParam.getUserPassword(), user.getUserPassword())) {
|
||||
log.warn("密码错误: {}", requestParam.getUserAccount());
|
||||
throw new ServiceException("用户不存在或密码错误", ErrorCode.NOT_LOGIN_ERROR);
|
||||
}
|
||||
if (!BCrypt.checkpw(requestParam.getUserPassword(), user.getUserPassword())) {
|
||||
log.warn("密码错误: {}", requestParam.getUserAccount());
|
||||
throw new ServiceException("用户不存在或密码错误", ErrorCode.NOT_LOGIN_ERROR);
|
||||
}
|
||||
|
||||
// 生成 JWT
|
||||
log.info("正在生成JWT token...");
|
||||
String accessToken = jwtUtil.generateAccessToken(user);
|
||||
String refreshToken = jwtUtil.generateRefreshToken(user.getId());
|
||||
// 生成 JWT
|
||||
log.info("正在生成JWT token...");
|
||||
String accessToken = jwtUtil.generateAccessToken(user);
|
||||
String refreshToken = jwtUtil.generateRefreshToken(user.getId());
|
||||
|
||||
UserLoginResponseDTO resp = new UserLoginResponseDTO();
|
||||
resp.setId(user.getId());
|
||||
resp.setUserAccount(user.getUserAccount());
|
||||
resp.setAccessToken(accessToken);
|
||||
resp.setRefreshToken(refreshToken);
|
||||
resp.setAccessTokenExpireTime(jwtPropertiesConfiguration.getAccessExpire());
|
||||
resp.setRefreshTokenExpireTime(jwtPropertiesConfiguration.getRefreshExpire());
|
||||
// refresh token存入到REDIS里面
|
||||
stringRedisTemplate.opsForValue()
|
||||
.set(String.format(RedisKeyConstants.REFRESH_TOKEN_KEY_PREFIX, user.getId()), refreshToken,
|
||||
jwtPropertiesConfiguration.getRefreshExpire(), TimeUnit.MILLISECONDS);
|
||||
UserLoginResponseDTO resp = new UserLoginResponseDTO();
|
||||
resp.setId(user.getId());
|
||||
resp.setUserAccount(user.getUserAccount());
|
||||
resp.setAccessToken(accessToken);
|
||||
resp.setRefreshToken(refreshToken);
|
||||
resp.setAccessTokenExpireTime(jwtPropertiesConfiguration.getAccessExpire());
|
||||
resp.setRefreshTokenExpireTime(jwtPropertiesConfiguration.getRefreshExpire());
|
||||
// refresh token存入到REDIS里面
|
||||
stringRedisTemplate.opsForValue()
|
||||
.set(String.format(RedisKeyConstants.REFRESH_TOKEN_KEY_PREFIX, user.getId()), refreshToken,
|
||||
jwtPropertiesConfiguration.getRefreshExpire(), TimeUnit.MILLISECONDS);
|
||||
|
||||
log.info("用户登录成功: userId={}, userAccount={}", user.getId(), user.getUserAccount());
|
||||
return resp;
|
||||
}
|
||||
log.info("用户登录成功: userId={}, userAccount={}", user.getId(), user.getUserAccount());
|
||||
return resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新access token,使用refresh token
|
||||
* @param refreshToken
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public UserLoginResponseDTO refreshToken(String refreshToken) {
|
||||
UserLoginResponseDTO userLoginResponseDTO = new UserLoginResponseDTO();
|
||||
if (!jwtUtil.isTokenValid(refreshToken)) {
|
||||
throw new ServiceException("Refresh Token 已过期");
|
||||
}
|
||||
/**
|
||||
* 更新access token,使用refresh token
|
||||
*
|
||||
* @param refreshToken
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public UserLoginResponseDTO refreshToken(String refreshToken) {
|
||||
UserLoginResponseDTO userLoginResponseDTO = new UserLoginResponseDTO();
|
||||
if (!jwtUtil.isTokenValid(refreshToken)) {
|
||||
throw new ServiceException("Refresh Token 已过期");
|
||||
}
|
||||
|
||||
Long userId = Long.valueOf(jwtUtil.parseClaims(refreshToken).getSubject());
|
||||
Long userId = Long.valueOf(jwtUtil.parseClaims(refreshToken).getSubject());
|
||||
|
||||
String cacheKey = String.format(RedisKeyConstants.REFRESH_TOKEN_KEY_PREFIX, userId);
|
||||
String cacheValue = stringRedisTemplate.opsForValue().get(cacheKey);
|
||||
String cacheKey = String.format(RedisKeyConstants.REFRESH_TOKEN_KEY_PREFIX, userId);
|
||||
String cacheValue = stringRedisTemplate.opsForValue().get(cacheKey);
|
||||
|
||||
if (cacheValue == null || !cacheValue.equals(refreshToken)) {
|
||||
throw new ServiceException("Refresh Token 已失效");
|
||||
}
|
||||
if (cacheValue == null || !cacheValue.equals(refreshToken)) {
|
||||
throw new ServiceException("Refresh Token 已失效");
|
||||
}
|
||||
|
||||
// 再次签发新的 Access Token
|
||||
// 此处你需要查用户,拿 userName, role
|
||||
Result<UserAuthRespDTO> userResult = userClient.getUserById(String.valueOf(userId));
|
||||
if (userResult.isFail()) {
|
||||
log.error("通过id查找用户失败:{}", userResult.getMessage());
|
||||
throw new ServiceException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
UserAuthRespDTO user = userResult.getData();
|
||||
String newAccessToken = jwtUtil.generateAccessToken(user);
|
||||
// 再次签发新的 Access Token
|
||||
// 此处你需要查用户,拿 userName, role
|
||||
Result<UserAuthRespDTO> userResult = userClient.getUserById(String.valueOf(userId));
|
||||
if (userResult.isFail()) {
|
||||
log.error("通过id查找用户失败:{}", userResult.getMessage());
|
||||
throw new ServiceException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
UserAuthRespDTO user = userResult.getData();
|
||||
String newAccessToken = jwtUtil.generateAccessToken(user);
|
||||
|
||||
// 设置refresh token和access token
|
||||
userLoginResponseDTO.setRefreshToken(refreshToken);
|
||||
userLoginResponseDTO.setAccessToken(newAccessToken);
|
||||
userLoginResponseDTO.setAccessTokenExpireTime(jwtPropertiesConfiguration.getAccessExpire());
|
||||
userLoginResponseDTO.setRefreshTokenExpireTime(jwtPropertiesConfiguration.getRefreshExpire());
|
||||
return userLoginResponseDTO;
|
||||
}
|
||||
// 设置refresh token和access token
|
||||
userLoginResponseDTO.setRefreshToken(refreshToken);
|
||||
userLoginResponseDTO.setAccessToken(newAccessToken);
|
||||
userLoginResponseDTO.setAccessTokenExpireTime(jwtPropertiesConfiguration.getAccessExpire());
|
||||
userLoginResponseDTO.setRefreshTokenExpireTime(jwtPropertiesConfiguration.getRefreshExpire());
|
||||
return userLoginResponseDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证token的有效性
|
||||
* @param accessToken 访问令牌
|
||||
* @return token是否有效
|
||||
*/
|
||||
@Override
|
||||
public Boolean validateToken(String accessToken) {
|
||||
try {
|
||||
// 1. 检查token格式
|
||||
if (accessToken == null || accessToken.trim().isEmpty()) {
|
||||
log.warn("Access token is null or empty");
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 验证token的有效性
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @return token是否有效
|
||||
*/
|
||||
@Override
|
||||
public Boolean validateToken(String accessToken) {
|
||||
try {
|
||||
// 1. 检查token格式
|
||||
if (accessToken == null || accessToken.trim().isEmpty()) {
|
||||
log.warn("Access token is null or empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 验证token签名和过期时间
|
||||
if (!jwtUtil.isTokenValid(accessToken)) {
|
||||
log.warn("Access token is invalid or expired");
|
||||
return false;
|
||||
}
|
||||
// 2. 验证token签名和过期时间
|
||||
if (!jwtUtil.isTokenValid(accessToken)) {
|
||||
log.warn("Access token is invalid or expired");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 解析token获取用户信息
|
||||
String userId = jwtUtil.parseClaims(accessToken).getSubject();
|
||||
if (userId == null) {
|
||||
log.warn("Access token does not contain valid user id");
|
||||
return false;
|
||||
}
|
||||
// 3. 解析token获取用户信息
|
||||
String userId = jwtUtil.parseClaims(accessToken).getSubject();
|
||||
if (userId == null) {
|
||||
log.warn("Access token does not contain valid user id");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 验证用户是否存在(可选,增加安全性)
|
||||
Result<UserAuthRespDTO> userResult = userClient.getUserById(userId);
|
||||
if (userResult.isFail() || userResult.getData() == null) {
|
||||
log.warn("User not found for id: {}", userId);
|
||||
return false;
|
||||
}
|
||||
// 4. 验证用户是否存在(可选,增加安全性)
|
||||
Result<UserAuthRespDTO> userResult = userClient.getUserById(userId);
|
||||
if (userResult.isFail() || userResult.getData() == null) {
|
||||
log.warn("User not found for id: {}", userId);
|
||||
return false;
|
||||
}
|
||||
|
||||
log.debug("Access token validation successful for user: {}", userId);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("Error validating access token", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserAuthRespDTO getUserInfo(String accessToken) {
|
||||
|
||||
// 1. 参数校验
|
||||
if (accessToken == null || accessToken.isBlank()) {
|
||||
log.warn("Access token is null or empty");
|
||||
throw new ClientException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
|
||||
// 2. token 校验
|
||||
if (!jwtUtil.isTokenValid(accessToken)) {
|
||||
log.warn("Access token is invalid or expired");
|
||||
throw new ClientException(ErrorCode.NOT_LOGIN_ERROR);
|
||||
}
|
||||
|
||||
// 3. 解析 token
|
||||
String userId;
|
||||
try {
|
||||
userId = jwtUtil.parseClaims(accessToken).getSubject();
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to parse access token", e);
|
||||
throw new ClientException(ErrorCode.NOT_LOGIN_ERROR);
|
||||
}
|
||||
|
||||
if (userId == null) {
|
||||
throw new ClientException(ErrorCode.NOT_LOGIN_ERROR);
|
||||
}
|
||||
|
||||
// 4. 查询用户信息(IO 操作)
|
||||
Result<UserAuthRespDTO> userResult;
|
||||
try {
|
||||
userResult = userClient.getUserById(userId);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call user service", e);
|
||||
throw new ClientException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
if (userResult == null || userResult.isFail()) {
|
||||
throw new ClientException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
if (userResult.getData() == null) {
|
||||
throw new ClientException(ErrorCode.NOT_FOUND_ERROR);
|
||||
}
|
||||
|
||||
return userResult.getData();
|
||||
}
|
||||
|
||||
log.debug("Access token validation successful for user: {}", userId);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Error validating access token", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class JwtUtil {
|
||||
claims.put("role", user.getUserRole());
|
||||
|
||||
return Jwts.builder()
|
||||
.subject(user.getUserAccount())
|
||||
.subject(String.valueOf(user.getId()))
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + jwtConfig.getAccessExpire()))
|
||||
.claims(claims)
|
||||
|
||||
@@ -2,34 +2,40 @@ package cn.meowrain.aioj.backend.framework.core.errorcode;
|
||||
|
||||
public enum ErrorCode implements IErrorCode {
|
||||
|
||||
SUCCESS("0", "ok"), PARAMS_ERROR("40000", "请求参数错误"), NOT_LOGIN_ERROR("40100", "未登录"), NO_AUTH_ERROR("40101", "无权限"),
|
||||
NOT_FOUND_ERROR("40400", "请求数据不存在"), FORBIDDEN_ERROR("40300", "禁止访问"), SYSTEM_ERROR("50000", "系统内部异常"),
|
||||
OPERATION_ERROR("50001", "操作失败"), API_REQUEST_ERROR("50010", "接口调用失败");
|
||||
SUCCESS("0", "ok"),
|
||||
PARAMS_ERROR("40000", "请求参数错误"),
|
||||
NOT_LOGIN_ERROR("40100", "未登录"),
|
||||
NO_AUTH_ERROR("40101", "无权限"),
|
||||
NOT_FOUND_ERROR("40400", "请求数据不存在"),
|
||||
FORBIDDEN_ERROR("40300", "禁止访问"),
|
||||
SYSTEM_ERROR("50000", "系统内部异常"),
|
||||
OPERATION_ERROR("50001", "操作失败"),
|
||||
API_REQUEST_ERROR("50010", "接口调用失败");
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
|
||||
private final String code;
|
||||
private final String code;
|
||||
|
||||
/**
|
||||
* 信息
|
||||
*/
|
||||
private final String message;
|
||||
/**
|
||||
* 信息
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
ErrorCode(String code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
ErrorCode(String code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String code() {
|
||||
return code;
|
||||
}
|
||||
@Override
|
||||
public String code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String message() {
|
||||
return message;
|
||||
}
|
||||
@Override
|
||||
public String message() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public final class Results {
|
||||
*/
|
||||
public static Result<Void> failure(AbstractException exception) {
|
||||
String errorCode = Optional.ofNullable(exception.getErrorCode()).orElse(ErrorCode.SYSTEM_ERROR.code());
|
||||
String errorMessage = Optional.ofNullable(exception.getMessage()).orElse(ErrorCode.SYSTEM_ERROR.message());
|
||||
String errorMessage = Optional.ofNullable(exception.getErrorMessage()).orElse(ErrorCode.SYSTEM_ERROR.message());
|
||||
|
||||
return new Result<Void>().setCode(errorCode).setMessage(errorMessage);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user