登录接口
This commit is contained in:
@@ -6,13 +6,10 @@ import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import static com.bicloud.common.utils.RedisConstants.JWT_BLACKLIST_KEY;
|
||||
|
||||
/**
|
||||
* JWT认证拦截器
|
||||
*/
|
||||
@@ -23,9 +20,6 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
|
||||
@Resource
|
||||
private JwtUtils jwtUtils;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 1. 从请求头获取Token
|
||||
@@ -47,17 +41,7 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 检查Token是否在黑名单中
|
||||
String blacklistKey = JWT_BLACKLIST_KEY + token;
|
||||
Boolean isBlacklisted = stringRedisTemplate.hasKey(blacklistKey);
|
||||
if (Boolean.TRUE.equals(isBlacklisted)) {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
response.getWriter().write("{\"code\":401,\"message\":\"Token已失效,请重新登录!\"}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5. 解析Token,获取用户信息
|
||||
// 4. 解析Token,获取用户信息
|
||||
Long userId = jwtUtils.getUserIdFromToken(token);
|
||||
String username = jwtUtils.getUsernameFromToken(token);
|
||||
|
||||
@@ -68,7 +52,7 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 6. 将用户信息存入ThreadLocal
|
||||
// 5. 将用户信息存入ThreadLocal
|
||||
UserContext.setUserId(userId);
|
||||
UserContext.setUsername(username);
|
||||
|
||||
|
||||
@@ -36,27 +36,11 @@ public class JwtUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成AccessToken
|
||||
* 生成Token
|
||||
*/
|
||||
public String generateAccessToken(Long userId, String username) {
|
||||
public String generateToken(Long userId, String username) {
|
||||
Date now = new Date();
|
||||
Date expiryDate = new Date(now.getTime() + jwtProperties.getAccessTokenExpiration() * 1000);
|
||||
|
||||
return Jwts.builder()
|
||||
.subject(String.valueOf(userId))
|
||||
.claim("username", username)
|
||||
.issuedAt(now)
|
||||
.expiration(expiryDate)
|
||||
.signWith(secretKey)
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成RefreshToken
|
||||
*/
|
||||
public String generateRefreshToken(Long userId, String username) {
|
||||
Date now = new Date();
|
||||
Date expiryDate = new Date(now.getTime() + jwtProperties.getRefreshTokenExpiration() * 1000);
|
||||
Date expiryDate = new Date(now.getTime() + jwtProperties.getTokenExpiration() * 1000);
|
||||
|
||||
return Jwts.builder()
|
||||
.subject(String.valueOf(userId))
|
||||
@@ -127,24 +111,11 @@ public class JwtUtils {
|
||||
* 从请求头中提取Token
|
||||
*/
|
||||
public String extractToken(HttpServletRequest request) {
|
||||
String bearerToken = request.getHeader(jwtProperties.getTokenHeader());
|
||||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(jwtProperties.getTokenPrefix())) {
|
||||
return bearerToken.substring(jwtProperties.getTokenPrefix().length());
|
||||
String token = request.getHeader(jwtProperties.getTokenHeader());
|
||||
if (StringUtils.hasText(token)) {
|
||||
return token;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Token剩余有效时间(秒)
|
||||
*/
|
||||
public Long getTokenRemainingTime(String token) {
|
||||
Claims claims = parseToken(token);
|
||||
if (claims == null) {
|
||||
return 0L;
|
||||
}
|
||||
Date expiration = claims.getExpiration();
|
||||
long remainingTime = (expiration.getTime() - System.currentTimeMillis()) / 1000;
|
||||
return Math.max(remainingTime, 0L);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,22 +18,12 @@ public class JwtProperties {
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* AccessToken过期时间(秒)
|
||||
* Token过期时间(秒)
|
||||
*/
|
||||
private Long accessTokenExpiration;
|
||||
|
||||
/**
|
||||
* RefreshToken过期时间(秒)
|
||||
*/
|
||||
private Long refreshTokenExpiration;
|
||||
private Long tokenExpiration;
|
||||
|
||||
/**
|
||||
* Token请求头名称
|
||||
*/
|
||||
private String tokenHeader;
|
||||
|
||||
/**
|
||||
* Token前缀
|
||||
*/
|
||||
private String tokenPrefix;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.bicloud.config;
|
||||
|
||||
|
||||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityScheme;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
|
||||
@@ -30,8 +30,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
// 用户相关放行路径
|
||||
"/user/code",
|
||||
"/user/register",
|
||||
"/user/login",
|
||||
"/user/refresh-token"
|
||||
"/user/login"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,16 +58,6 @@ public class UserController {
|
||||
return Result.success(loginVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新Token
|
||||
*/
|
||||
@PostMapping("/refresh-token")
|
||||
@Operation(summary = "刷新Token")
|
||||
public Result<String> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||
String newAccessToken = userService.refreshToken(refreshToken);
|
||||
return Result.success(newAccessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登出
|
||||
*/
|
||||
|
||||
@@ -17,15 +17,9 @@ import lombok.NoArgsConstructor;
|
||||
public class LoginVo {
|
||||
|
||||
@Schema(description = "访问令牌")
|
||||
private String accessToken;
|
||||
private String token;
|
||||
|
||||
@Schema(description = "刷新令牌")
|
||||
private String refreshToken;
|
||||
|
||||
@Schema(description = "令牌类型", example = "Bearer")
|
||||
private String tokenType;
|
||||
|
||||
@Schema(description = "访问令牌过期时间(秒)", example = "7200")
|
||||
@Schema(description = "令牌过期时间(秒)", example = "86400")
|
||||
private Long expiresIn;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
|
||||
@@ -18,11 +18,6 @@ public interface UserService {
|
||||
*/
|
||||
LoginVo login(LoginDto loginDto);
|
||||
|
||||
/**
|
||||
* 刷新Token
|
||||
*/
|
||||
String refreshToken(String refreshToken);
|
||||
|
||||
/**
|
||||
* 用户登出
|
||||
*/
|
||||
|
||||
@@ -189,61 +189,21 @@ public class UserServiceImpl implements UserService {
|
||||
}
|
||||
|
||||
// 4. 生成Token
|
||||
String accessToken = jwtUtils.generateAccessToken(user.getId(), user.getUsername());
|
||||
String refreshToken = jwtUtils.generateRefreshToken(user.getId(), user.getUsername());
|
||||
String token = jwtUtils.generateToken(user.getId(), user.getUsername());
|
||||
|
||||
// 5. 构建返回结果
|
||||
return LoginVo.builder()
|
||||
.accessToken(accessToken)
|
||||
.refreshToken(refreshToken)
|
||||
.tokenType("Bearer")
|
||||
.expiresIn(jwtProperties.getAccessTokenExpiration())
|
||||
.token(token)
|
||||
.expiresIn(jwtProperties.getTokenExpiration())
|
||||
.userId(user.getId())
|
||||
.username(user.getUsername())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refreshToken(String refreshToken) {
|
||||
// 1. 验证RefreshToken
|
||||
if (!jwtUtils.validateToken(refreshToken)) {
|
||||
throw new BusinessException("RefreshToken无效或已过期!");
|
||||
}
|
||||
|
||||
// 2. 检查黑名单
|
||||
String blacklistKey = JWT_BLACKLIST_KEY + refreshToken;
|
||||
Boolean isBlacklisted = stringRedisTemplate.hasKey(blacklistKey);
|
||||
if (Boolean.TRUE.equals(isBlacklisted)) {
|
||||
throw new BusinessException("Token已失效,请重新登录!");
|
||||
}
|
||||
|
||||
// 3. 从Token中获取用户信息
|
||||
Long userId = jwtUtils.getUserIdFromToken(refreshToken);
|
||||
String username = jwtUtils.getUsernameFromToken(refreshToken);
|
||||
|
||||
if (userId == null || username == null) {
|
||||
throw new BusinessException("Token解析失败!");
|
||||
}
|
||||
|
||||
// 4. 生成新的AccessToken
|
||||
return jwtUtils.generateAccessToken(userId, username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout(String token) {
|
||||
// 1. 将Token加入黑名单
|
||||
String blacklistKey = JWT_BLACKLIST_KEY + token;
|
||||
Long remainingTime = jwtUtils.getTokenRemainingTime(token);
|
||||
|
||||
// 2. 设置黑名单过期时间为Token剩余有效时间
|
||||
stringRedisTemplate.opsForValue().set(
|
||||
blacklistKey,
|
||||
"1",
|
||||
remainingTime,
|
||||
TimeUnit.SECONDS
|
||||
);
|
||||
|
||||
log.info("用户登出成功,Token已加入黑名单");
|
||||
// 简化版:不使用黑名单,由前端删除token即可
|
||||
log.info("用户登出成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -55,7 +55,5 @@ logging:
|
||||
|
||||
jwt:
|
||||
secret: bicloud-jwt-secret-key-2024-spring-boot-application-secure-token-generation
|
||||
access-token-expiration: 7200
|
||||
refresh-token-expiration: 604800
|
||||
token-expiration: 86400
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
|
||||
Reference in New Issue
Block a user