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:
2026-01-07 20:16:19 +08:00
parent cacf7ed820
commit 6f0ee9bbf5
7 changed files with 221 additions and 142 deletions

View File

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

View File

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

View File

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

View File

@@ -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;
@@ -88,6 +89,7 @@ public class AuthServiceImpl implements AuthService {
/**
* 更新access token使用refresh token
*
* @param refreshToken
* @return
*/
@@ -127,6 +129,7 @@ public class AuthServiceImpl implements AuthService {
/**
* 验证token的有效性
*
* @param accessToken 访问令牌
* @return token是否有效
*/
@@ -161,11 +164,59 @@ public class AuthServiceImpl implements AuthService {
log.debug("Access token validation successful for user: {}", userId);
return true;
}
catch (Exception e) {
} 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();
}
}

View File

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

View File

@@ -2,9 +2,15 @@ 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", "接口调用失败");
/**
* 状态码

View File

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