登录接口

This commit is contained in:
dww
2026-02-03 16:36:01 +08:00
parent caa699a6cd
commit 3808449d4d
10 changed files with 21 additions and 138 deletions

View File

@@ -6,13 +6,10 @@ import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import static com.bicloud.common.utils.RedisConstants.JWT_BLACKLIST_KEY;
/** /**
* JWT认证拦截器 * JWT认证拦截器
*/ */
@@ -23,9 +20,6 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
@Resource @Resource
private JwtUtils jwtUtils; private JwtUtils jwtUtils;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 从请求头获取Token // 1. 从请求头获取Token
@@ -47,17 +41,7 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
return false; return false;
} }
// 4. 检查Token是否在黑名单中 // 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获取用户信息
Long userId = jwtUtils.getUserIdFromToken(token); Long userId = jwtUtils.getUserIdFromToken(token);
String username = jwtUtils.getUsernameFromToken(token); String username = jwtUtils.getUsernameFromToken(token);
@@ -68,7 +52,7 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
return false; return false;
} }
// 6. 将用户信息存入ThreadLocal // 5. 将用户信息存入ThreadLocal
UserContext.setUserId(userId); UserContext.setUserId(userId);
UserContext.setUsername(username); UserContext.setUsername(username);

View File

@@ -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 now = new Date();
Date expiryDate = new Date(now.getTime() + jwtProperties.getAccessTokenExpiration() * 1000); Date expiryDate = new Date(now.getTime() + jwtProperties.getTokenExpiration() * 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);
return Jwts.builder() return Jwts.builder()
.subject(String.valueOf(userId)) .subject(String.valueOf(userId))
@@ -127,24 +111,11 @@ public class JwtUtils {
* 从请求头中提取Token * 从请求头中提取Token
*/ */
public String extractToken(HttpServletRequest request) { public String extractToken(HttpServletRequest request) {
String bearerToken = request.getHeader(jwtProperties.getTokenHeader()); String token = request.getHeader(jwtProperties.getTokenHeader());
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(jwtProperties.getTokenPrefix())) { if (StringUtils.hasText(token)) {
return bearerToken.substring(jwtProperties.getTokenPrefix().length()); return token;
} }
return null; 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);
}
} }

View File

@@ -18,22 +18,12 @@ public class JwtProperties {
private String secret; private String secret;
/** /**
* AccessToken过期时间 * Token过期时间
*/ */
private Long accessTokenExpiration; private Long tokenExpiration;
/**
* RefreshToken过期时间
*/
private Long refreshTokenExpiration;
/** /**
* Token请求头名称 * Token请求头名称
*/ */
private String tokenHeader; private String tokenHeader;
/**
* Token前缀
*/
private String tokenPrefix;
} }

View File

@@ -1,6 +1,8 @@
package com.bicloud.config; 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.OpenAPI;
import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License; import io.swagger.v3.oas.models.info.License;

View File

@@ -30,8 +30,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
// 用户相关放行路径 // 用户相关放行路径
"/user/code", "/user/code",
"/user/register", "/user/register",
"/user/login", "/user/login"
"/user/refresh-token"
); );
} }
} }

View File

@@ -58,16 +58,6 @@ public class UserController {
return Result.success(loginVo); 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);
}
/** /**
* 用户登出 * 用户登出
*/ */

View File

@@ -17,15 +17,9 @@ import lombok.NoArgsConstructor;
public class LoginVo { public class LoginVo {
@Schema(description = "访问令牌") @Schema(description = "访问令牌")
private String accessToken; private String token;
@Schema(description = "刷新令牌") @Schema(description = "令牌过期时间(秒)", example = "86400")
private String refreshToken;
@Schema(description = "令牌类型", example = "Bearer")
private String tokenType;
@Schema(description = "访问令牌过期时间(秒)", example = "7200")
private Long expiresIn; private Long expiresIn;
@Schema(description = "用户ID") @Schema(description = "用户ID")

View File

@@ -18,11 +18,6 @@ public interface UserService {
*/ */
LoginVo login(LoginDto loginDto); LoginVo login(LoginDto loginDto);
/**
* 刷新Token
*/
String refreshToken(String refreshToken);
/** /**
* 用户登出 * 用户登出
*/ */

View File

@@ -189,61 +189,21 @@ public class UserServiceImpl implements UserService {
} }
// 4. 生成Token // 4. 生成Token
String accessToken = jwtUtils.generateAccessToken(user.getId(), user.getUsername()); String token = jwtUtils.generateToken(user.getId(), user.getUsername());
String refreshToken = jwtUtils.generateRefreshToken(user.getId(), user.getUsername());
// 5. 构建返回结果 // 5. 构建返回结果
return LoginVo.builder() return LoginVo.builder()
.accessToken(accessToken) .token(token)
.refreshToken(refreshToken) .expiresIn(jwtProperties.getTokenExpiration())
.tokenType("Bearer")
.expiresIn(jwtProperties.getAccessTokenExpiration())
.userId(user.getId()) .userId(user.getId())
.username(user.getUsername()) .username(user.getUsername())
.build(); .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 @Override
public void logout(String token) { public void logout(String token) {
// 1. 将Token加入黑名单 // 简化版不使用黑名单由前端删除token即可
String blacklistKey = JWT_BLACKLIST_KEY + token; log.info("用户登出成功");
Long remainingTime = jwtUtils.getTokenRemainingTime(token);
// 2. 设置黑名单过期时间为Token剩余有效时间
stringRedisTemplate.opsForValue().set(
blacklistKey,
"1",
remainingTime,
TimeUnit.SECONDS
);
log.info("用户登出成功Token已加入黑名单");
} }
@Override @Override

View File

@@ -55,7 +55,5 @@ logging:
jwt: jwt:
secret: bicloud-jwt-secret-key-2024-spring-boot-application-secure-token-generation secret: bicloud-jwt-secret-key-2024-spring-boot-application-secure-token-generation
access-token-expiration: 7200 token-expiration: 86400
refresh-token-expiration: 604800
token-header: Authorization token-header: Authorization
token-prefix: "Bearer "