diff --git a/aioj-backend-auth/pom.xml b/aioj-backend-auth/pom.xml
index ce205b0..0006c6b 100644
--- a/aioj-backend-auth/pom.xml
+++ b/aioj-backend-auth/pom.xml
@@ -96,5 +96,11 @@
spring-cloud-starter-loadbalancer
4.3.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
\ No newline at end of file
diff --git a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/clients/UserClient.java b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/clients/UserClient.java
index 3da69ce..6b77060 100644
--- a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/clients/UserClient.java
+++ b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/clients/UserClient.java
@@ -10,4 +10,7 @@ import org.springframework.web.bind.annotation.RequestParam;
public interface UserClient {
@GetMapping("/inner/get-by-username")
Result getUserByUserName(@RequestParam("userAccount") String userAccount);
+
+ @GetMapping("/inner/get-by-userid")
+ public Result getUserById(@RequestParam("userId") String userid);
}
diff --git a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/config/JwtPropertiesConfiguration.java b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/config/properties/JwtPropertiesConfiguration.java
similarity index 69%
rename from aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/config/JwtPropertiesConfiguration.java
rename to aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/config/properties/JwtPropertiesConfiguration.java
index eb5b4cc..5dfd246 100644
--- a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/config/JwtPropertiesConfiguration.java
+++ b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/config/properties/JwtPropertiesConfiguration.java
@@ -1,4 +1,4 @@
-package cn.meowrain.aioj.backend.auth.config;
+package cn.meowrain.aioj.backend.auth.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -17,5 +17,9 @@ public class JwtPropertiesConfiguration {
/**
* 过期时间(单位:毫秒)
*/
- private Long expire;
+ private long accessExpire; // access token TTL
+ /**
+ * 刷新令牌时间
+ */
+ private long refreshExpire; // refresh token TTL
}
diff --git a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/controller/AuthController.java b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/controller/AuthController.java
index ccf7337..bf8b590 100644
--- a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/controller/AuthController.java
+++ b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/controller/AuthController.java
@@ -5,21 +5,16 @@ import cn.meowrain.aioj.backend.auth.dto.resp.UserLoginResponseDTO;
import cn.meowrain.aioj.backend.auth.service.AuthService;
import cn.meowrain.aioj.backend.framework.web.Results;
import cn.meowrain.aioj.backend.framework.web.Result;
-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 lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
@RestController
+@RequiredArgsConstructor
@RequestMapping("/v1/auth")
public class AuthController {
private final AuthService authService;
- public AuthController(AuthService authService) {
- this.authService = authService;
- }
-
@PostMapping("/login")
public Result login(@RequestBody UserLoginRequestDTO userLoginRequest) {
UserLoginResponseDTO userLoginResponse = authService.userLogin(userLoginRequest);
@@ -27,9 +22,16 @@ public class AuthController {
}
+ @PostMapping("/refresh")
+ public Result refresh(@RequestParam String refreshToken) {
+ return Results.success(authService.refreshToken(refreshToken));
+ }
+
@PostMapping("/auth")
public Result auth(@RequestBody UserLoginRequestDTO userLoginRequest) {
UserLoginResponseDTO userLoginResponseDTO = authService.userLogin(userLoginRequest);
- return Results.success(userLoginResponseDTO.getToken());
+ return Results.success(userLoginResponseDTO.getAccessToken());
}
+
+
}
diff --git a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/dto/resp/UserLoginResponseDTO.java b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/dto/resp/UserLoginResponseDTO.java
index d9f0d7e..ad057f7 100644
--- a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/dto/resp/UserLoginResponseDTO.java
+++ b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/dto/resp/UserLoginResponseDTO.java
@@ -22,52 +22,9 @@ public class UserLoginResponseDTO implements Serializable {
*/
private String unionId;
- /**
- * 公众号openId
- */
- private String mpOpenId;
-
- /**
- * 用户昵称
- */
- private String userName;
-
- /**
- * 用户头像
- */
- private String userAvatar;
-
- /**
- * 用户简介
- */
- private String userProfile;
-
- /**
- * 用户角色:user/admin/ban
- */
- private String userRole;
-
- /**
- * 创建时间
- */
- private Date createTime;
-
- /**
- * 更新时间
- */
- private Date updateTime;
-
- /**
- * 是否删除
- */
-
- private Integer isDelete;
-
-
- /**
- * JWT令牌(登录成功返回)
- */
- private String token;
+ private String accessToken;
+ private String refreshToken;
+ private Long expire;
private static final long serialVersionUID = 1L;
}
diff --git a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/service/AuthService.java b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/service/AuthService.java
index 92cf15c..a3ef754 100644
--- a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/service/AuthService.java
+++ b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/service/AuthService.java
@@ -11,4 +11,10 @@ public interface AuthService {
*/
UserLoginResponseDTO userLogin(UserLoginRequestDTO request);
+ /**
+ * 刷新token
+ * @param refreshToken
+ * @return
+ */
+ UserLoginResponseDTO refreshToken(String refreshToken);
}
diff --git a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/service/impl/AuthServiceImpl.java b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/service/impl/AuthServiceImpl.java
index f1aaf7b..0113b09 100644
--- a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/service/impl/AuthServiceImpl.java
+++ b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/service/impl/AuthServiceImpl.java
@@ -3,7 +3,9 @@ package cn.meowrain.aioj.backend.auth.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.meowrain.aioj.backend.auth.clients.UserClient;
+import cn.meowrain.aioj.backend.auth.common.constants.RedisKeyConstants;
import cn.meowrain.aioj.backend.auth.common.enums.ChainMarkEnums;
+import cn.meowrain.aioj.backend.auth.config.properties.JwtPropertiesConfiguration;
import cn.meowrain.aioj.backend.auth.dto.chains.context.UserLoginRequestParamVerifyContext;
import cn.meowrain.aioj.backend.auth.dto.req.UserLoginRequestDTO;
import cn.meowrain.aioj.backend.auth.dto.resp.UserAuthRespDTO;
@@ -15,8 +17,11 @@ import cn.meowrain.aioj.backend.framework.exception.ServiceException;
import cn.meowrain.aioj.backend.framework.web.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
+import java.util.concurrent.TimeUnit;
+
@Component
@RequiredArgsConstructor
@Slf4j
@@ -24,6 +29,8 @@ public class AuthServiceImpl implements AuthService {
private final JwtUtil jwtUtil;
private final UserLoginRequestParamVerifyContext userLoginRequestParamVerifyContext;
private final UserClient userClient;
+ private final StringRedisTemplate stringRedisTemplate;
+ private final JwtPropertiesConfiguration jwtPropertiesConfiguration;
@Override
public UserLoginResponseDTO userLogin(UserLoginRequestDTO requestParam) {
@@ -43,16 +50,57 @@ public class AuthServiceImpl implements AuthService {
throw new ServiceException("用户不存在或者密码错误", ErrorCode.NOT_LOGIN_ERROR);
}
// 生成 JWT
- String token = jwtUtil.generateToken(user);
+ String accessToken = jwtUtil.generateAccessToken(user);
+ String refreshToken = jwtUtil.generateRefreshToken(user.getId());
UserLoginResponseDTO resp = new UserLoginResponseDTO();
resp.setId(user.getId());
resp.setUserAccount(user.getUserAccount());
- resp.setUserAvatar(user.getUserAvatar());
- resp.setUserProfile(user.getUserProfile());
- resp.setUserRole(user.getUserRole());
- resp.setCreateTime(user.getCreateTime());
- resp.setUpdateTime(user.getUpdateTime());
- resp.setToken(token);
+ resp.setAccessToken(accessToken);
+ resp.setRefreshToken(refreshToken);
+
+ // refresh token存入到REDIS里面
+ stringRedisTemplate.opsForValue().set(
+ String.format(RedisKeyConstants.REFRESH_TOKEN_KEY_PREFIX, user.getId()),
+ refreshToken,
+ jwtPropertiesConfiguration.getRefreshExpire(),
+ TimeUnit.MILLISECONDS);
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 RuntimeException("Refresh Token 已过期");
+ }
+
+ Long userId = Long.valueOf(jwtUtil.parseClaims(refreshToken).getSubject());
+
+ String cacheKey = String.format(RedisKeyConstants.REFRESH_TOKEN_KEY_PREFIX, userId);
+ String cacheValue = stringRedisTemplate.opsForValue().get(cacheKey);
+
+ if (cacheValue == null || !cacheValue.equals(refreshToken)) {
+ throw new RuntimeException("Refresh Token 已失效");
+ }
+
+ // 再次签发新的 Access Token
+ // 此处你需要查用户,拿 userName, role
+ Result 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);
+ return userLoginResponseDTO;
+ }
}
diff --git a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/utils/JwtUtil.java b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/utils/JwtUtil.java
index 2382d65..6a361be 100644
--- a/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/utils/JwtUtil.java
+++ b/aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/utils/JwtUtil.java
@@ -1,6 +1,6 @@
package cn.meowrain.aioj.backend.auth.utils;
-import cn.meowrain.aioj.backend.auth.config.JwtPropertiesConfiguration;
+import cn.meowrain.aioj.backend.auth.config.properties.JwtPropertiesConfiguration;
import cn.meowrain.aioj.backend.auth.dto.resp.UserAuthRespDTO;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
@@ -13,32 +13,47 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Map;
-/**
- * JWT工具类
- */
@RequiredArgsConstructor
@Component
public class JwtUtil {
+
private final JwtPropertiesConfiguration jwtConfig;
private SecretKey getSigningKey() {
return Keys.hmacShaKeyFor(jwtConfig.getSecret().getBytes());
}
- public String generateToken(UserAuthRespDTO user) {
+ /** 生成 Access Token */
+ public String generateAccessToken(UserAuthRespDTO user) {
long now = System.currentTimeMillis();
+
Map claims = new HashMap<>();
claims.put("userId", user.getId());
+ claims.put("userName", user.getUserName());
claims.put("role", user.getUserRole());
+
return Jwts.builder()
.subject(user.getUserAccount())
.issuedAt(new Date(now))
- .expiration(new Date(now + jwtConfig.getExpire()))
+ .expiration(new Date(now + jwtConfig.getAccessExpire()))
.claims(claims)
.signWith(getSigningKey(), Jwts.SIG.HS256)
.compact();
}
+ /** 生成 Refresh Token(只含 userId) */
+ public String generateRefreshToken(Long userId) {
+ long now = System.currentTimeMillis();
+
+ return Jwts.builder()
+ .subject(String.valueOf(userId))
+ .issuedAt(new Date(now))
+ .expiration(new Date(now + jwtConfig.getRefreshExpire()))
+ .signWith(getSigningKey(), Jwts.SIG.HS256)
+ .compact();
+ }
+
+ /** 解析 Token */
public Claims parseClaims(String token) {
return Jwts.parser()
.verifyWith(getSigningKey())
@@ -47,12 +62,12 @@ public class JwtUtil {
.getPayload();
}
+ /** 校验 Token 是否过期 */
public boolean isTokenValid(String token) {
try {
Claims claims = parseClaims(token);
- Date expiration = claims.getExpiration();
- return expiration != null && expiration.after(new Date());
- } catch (Exception e) {
+ return claims.getExpiration().after(new Date());
+ } catch (Exception ignored) {
return false;
}
}
diff --git a/aioj-backend-auth/src/main/resources/application-dev.yml b/aioj-backend-auth/src/main/resources/application-dev.yml
index 94b9104..c817fc0 100644
--- a/aioj-backend-auth/src/main/resources/application-dev.yml
+++ b/aioj-backend-auth/src/main/resources/application-dev.yml
@@ -1,4 +1,9 @@
spring:
+ data:
+ redis:
+ host: 10.0.0.10
+ port: 6379
+ password: 123456
cloud:
nacos:
discovery:
diff --git a/aioj-backend-auth/src/main/resources/application.yml b/aioj-backend-auth/src/main/resources/application.yml
index 571f68a..b60a8b4 100644
--- a/aioj-backend-auth/src/main/resources/application.yml
+++ b/aioj-backend-auth/src/main/resources/application.yml
@@ -34,4 +34,5 @@ mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
jwt:
secret: "12345678901234567890123456789012" # 至少32字节!!
- expire: 86400000 # 24小时(单位:毫秒)
\ No newline at end of file
+ access-expire: 900000 # 24小时
+ refresh-expire: 604800000 # 7天
\ No newline at end of file
diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/controller/UserController.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/controller/UserController.java
index bbb47d9..d1b87e4 100644
--- a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/controller/UserController.java
+++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/controller/UserController.java
@@ -28,5 +28,10 @@ public class UserController {
return Results.success(userAuthDTO);
}
+ @GetMapping("/inner/get-by-userid")
+ public Result getUserById(@RequestParam("userId") String userid) {
+ UserAuthRespDTO userAuthRespDTO = userService.findAuthInfoByUserId(userid);
+ return Results.success(userAuthRespDTO);
+ }
}
diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/UserService.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/UserService.java
index 7fdf0d4..837105e 100644
--- a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/UserService.java
+++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/UserService.java
@@ -22,4 +22,9 @@ public interface UserService extends IService {
* @return
*/
UserAuthRespDTO findAuthInfoByUserAccount(String userAccount);
+
+ /**
+ * 根据用户id查找用户认证信息
+ */
+ UserAuthRespDTO findAuthInfoByUserId(String userId);
}
diff --git a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/UserServiceImpl.java b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/UserServiceImpl.java
index 7bc4fab..e69f9e6 100644
--- a/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/UserServiceImpl.java
+++ b/aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/service/impl/UserServiceImpl.java
@@ -30,7 +30,7 @@ public class UserServiceImpl extends ServiceImpl implements Us
@Override
public Long userRegister(UserRegisterRequestDTO request) {
UserAuthRespDTO authInfoByUserAccount = findAuthInfoByUserAccount(request.getUserAccount());
- if(authInfoByUserAccount!=null){
+ if (authInfoByUserAccount != null) {
throw new ClientException("重复创建用户");
}
@@ -40,7 +40,7 @@ public class UserServiceImpl extends ServiceImpl implements Us
// 使用 BCrypt 加密密码
Date now = new Date();
String salt = BCrypt.gensalt();
- String encryptPassword = BCrypt.hashpw(request.getUserPassword(),salt);
+ String encryptPassword = BCrypt.hashpw(request.getUserPassword(), salt);
User user = new User().setUserAccount(request.getUserAccount()).setUserPassword(encryptPassword)
.setUserRole("user").setCreateTime(now).setUpdateTime(now);
try {
@@ -59,10 +59,22 @@ public class UserServiceImpl extends ServiceImpl implements Us
public UserAuthRespDTO findAuthInfoByUserAccount(String userAccount) {
User one = this.lambdaQuery().eq(User::getUserAccount, userAccount).one();
UserAuthRespDTO userAuthDTO = new UserAuthRespDTO();
- if(one!=null){
+ if (one != null) {
BeanUtils.copyProperties(one, userAuthDTO);
return userAuthDTO;
}
return null;
}
+
+ @Override
+ public UserAuthRespDTO findAuthInfoByUserId(String userId) {
+ User one = this.lambdaQuery().eq(User::getId, userId).one();
+ UserAuthRespDTO userAuthDTO = new UserAuthRespDTO();
+ if (one != null) {
+ BeanUtils.copyProperties(one, userAuthDTO);
+ return userAuthDTO;
+ }
+ return null;
+
+ }
}