fix:refreshToken

This commit is contained in:
Xiang
2026-03-20 13:52:33 +08:00
parent 22f0b546ad
commit 816dfb2304
6 changed files with 101 additions and 0 deletions

View File

@@ -12,6 +12,7 @@ public enum Code01UserErrorCode implements BaseErrorCode {
USER_EXISTS("A1000102", "用户已存在"),
USER_LOGIN_ERROR("A1000103", "用户登录失败!"),
USER_REGISTER_ERROR("1000104", "用户注册失败!"),
REFRESH_TOKEN_NOT_EXISTS("1000105", "refreshToken不匹配")
;
private final String code;

View File

@@ -0,0 +1,25 @@
package com.xiang.xservice.auth.api.dto.req;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: xiang
* @Date: 2026-03-20 13:46
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RefreshRequest {
/**
* 用户名
*/
private String username;
/**
* refresh Token
*/
private String refreshToken;
}

View File

@@ -12,4 +12,6 @@ public class LoginResp {
private String username;
private String token;
private String refreshToken;
}

View File

@@ -2,6 +2,7 @@ package com.xiang.xservice.auth.server.controller;
import com.xiang.xservice.auth.api.api.TokenApi;
import com.xiang.xservice.auth.api.dto.req.LoginRequest;
import com.xiang.xservice.auth.api.dto.req.RefreshRequest;
import com.xiang.xservice.auth.api.dto.req.RegisterRequest;
import com.xiang.xservice.auth.api.dto.resp.LoginResp;
import com.xiang.xservice.auth.api.dto.resp.RegisterResp;
@@ -41,6 +42,20 @@ public class TokenController implements TokenApi {
}
}
@PostMapping("/publish/auth/refresh")
public Result<LoginResp> refresh(@RequestBody @NotNull(message = "请求参数不能为空") @Valid RefreshRequest request) {
try {
LoginResp login = userService.refresh(request);
return Result.data(login);
} catch (BusinessException e) {
log.error("【用户登录】用户登录失败,{}", e.getMessage(), e);
return Result.error(e.getMessage());
} catch (Exception e) {
log.error("【用户登录】用户登录失败,{}", e.getMessage(), e);
return Result.error();
}
}
@PostMapping("/public/user/userRegister")
public Result<RegisterResp> register(@RequestBody @Valid @NotNull(message = "请求参数不能为空") RegisterRequest request) {

View File

@@ -2,6 +2,7 @@ package com.xiang.xservice.auth.service.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiang.xservice.auth.api.dto.req.LoginRequest;
import com.xiang.xservice.auth.api.dto.req.RefreshRequest;
import com.xiang.xservice.auth.api.dto.req.RegisterRequest;
import com.xiang.xservice.auth.api.dto.req.user.UserAddRequest;
import com.xiang.xservice.auth.api.dto.req.user.UserDeptUpdateRequest;
@@ -38,4 +39,6 @@ public interface XUserService {
Boolean setUserRole(UserRoleUpdateRequest request);
UserDTO getUserDetail(Long userId);
LoginResp refresh(RefreshRequest request);
}

View File

@@ -9,6 +9,7 @@ import com.xiang.xservice.auth.api.code.Code01UserErrorCode;
import com.xiang.xservice.auth.api.code.Code02RoleErrorCode;
import com.xiang.xservice.auth.api.code.Code03DeptErrorCode;
import com.xiang.xservice.auth.api.dto.req.LoginRequest;
import com.xiang.xservice.auth.api.dto.req.RefreshRequest;
import com.xiang.xservice.auth.api.dto.req.RegisterRequest;
import com.xiang.xservice.auth.api.dto.req.user.UserAddRequest;
import com.xiang.xservice.auth.api.dto.req.user.UserDeptUpdateRequest;
@@ -123,6 +124,7 @@ public class XUserServiceImpl implements XUserService {
LoginResp loginResp = new LoginResp();
loginResp.setToken(user.getToken());
loginResp.setUsername(request.getUsername());
loginResp.setRefreshToken(user.getRefreshToken());
return loginResp;
}
}
@@ -159,6 +161,7 @@ public class XUserServiceImpl implements XUserService {
LoginResp loginResp = new LoginResp();
loginResp.setToken(token);
loginResp.setUsername(request.getUsername());
loginResp.setRefreshToken(refreshToken);
// 3. redis缓存token
redisService.set(RedisConstant.LOGIN_TOKEN + request.getUsername(), token, 3, TimeUnit.HOURS);
// 4. db 存储token
@@ -318,4 +321,56 @@ public class XUserServiceImpl implements XUserService {
}
return dto;
}
@Override
public LoginResp refresh(RefreshRequest request) {
XUser user = userMapper.selectByUsername(request.getUsername());
if (Objects.isNull(user)) {
throw new BusinessException(Code01UserErrorCode.USER_NOT_EXISTS);
}
if (StringUtils.isBlank(user.getRefreshToken()) || !user.getRefreshToken().equals(request.getRefreshToken())) {
throw new BusinessException(Code01UserErrorCode.REFRESH_TOKEN_NOT_EXISTS);
}
// 校验 refreshToken 是否过期
Jwt refreshJwt;
try {
refreshJwt = jwtDecoder.decode(request.getRefreshToken());
} catch (Exception e) {
log.error("【刷新token】refreshToken解析失败", e);
throw new BusinessException("refreshToken 无效或已过期");
}
if (Objects.isNull(refreshJwt.getExpiresAt()) || refreshJwt.getExpiresAt().isBefore(Instant.now())) {
throw new BusinessException("refreshToken 已过期,请重新登录");
}
// 查询角色
List<String> roleCodes = Lists.newArrayList();
List<XUserRole> userRoles = userRoleMapper.getByUserId(user.getId());
if (CollectionUtils.isNotEmpty(userRoles)) {
List<XRole> roles = roleMapper.getRoleByIds(userRoles.stream().map(XUserRole::getRoleId).collect(Collectors.toList()));
if (CollectionUtils.isNotEmpty(roles)) {
roleCodes.addAll(roles.stream().map(XRole::getCode).toList());
}
}
// 生成新的 accessToken
Instant now = Instant.now();
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuedAt(now)
.expiresAt(now.plus(3, ChronoUnit.HOURS))
.claim("userId", user.getId())
.claim("tenantId", user.getTenantId())
.claim("timestamp", System.currentTimeMillis())
.claim("username", request.getUsername())
.claim("authorities", roleCodes)
.build();
String newToken = jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
// 更新 Redis 和 DB
redisService.set(RedisConstant.LOGIN_TOKEN + request.getUsername(), newToken, 3, TimeUnit.HOURS);
user.setToken(newToken);
userMapper.update(user);
LoginResp loginResp = new LoginResp();
loginResp.setToken(newToken);
loginResp.setUsername(request.getUsername());
loginResp.setRefreshToken(request.getRefreshToken());
return loginResp;
}
}