feat: 更新 JWT 黑名单服务,支持令牌过期时间管理并添加定时清理功能
This commit is contained in:
parent
400a06f5a3
commit
244f0e7667
@ -2,8 +2,10 @@ package com.userauth.restuserauth;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
public class RestUserAuthApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.userauth.restuserauth.controller;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -85,8 +86,10 @@ public class AuthController {
|
||||
String bearerToken = request.getHeader("Authorization");
|
||||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
|
||||
String jwt = bearerToken.substring(7);
|
||||
// 将当前 JWT 加入黑名单
|
||||
jwtBlacklistService.blacklistToken(jwt);
|
||||
// 获取令牌的过期时间
|
||||
Date expirationDate = tokenProvider.getExpirationDateFromToken(jwt);
|
||||
// 将当前JWT及其过期时间加入黑名单
|
||||
jwtBlacklistService.blacklistToken(jwt, expirationDate);
|
||||
logger.info("令牌已加入黑名单:{}", jwt);
|
||||
}
|
||||
|
||||
|
@ -4,23 +4,28 @@ import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class JwtBlacklistService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JwtBlacklistService.class);
|
||||
|
||||
// 使用 ConcurrentHashMap 作为内存中的黑名单存储。
|
||||
// 在生产环境中,建议使用 Redis 等分布式缓存来支持多实例部署。
|
||||
private final Map<String, Date> blacklist = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 将令牌加入黑名单。
|
||||
* 将令牌及其过期时间加入黑名单。
|
||||
* @param token 要加入黑名单的 JWT。
|
||||
* @param expirationDate 令牌的过期时间。
|
||||
*/
|
||||
public void blacklistToken(String token) {
|
||||
// 为了简化,我们暂时不处理过期清理,直接加入。
|
||||
// 在实际应用中,可以存储令牌的过期时间,并定期清理已过期的令牌以防止内存泄漏。
|
||||
blacklist.put(token, new Date());
|
||||
public void blacklistToken(String token, Date expirationDate) {
|
||||
if (token != null && expirationDate != null) {
|
||||
blacklist.put(token, expirationDate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -31,4 +36,18 @@ public class JwtBlacklistService {
|
||||
public boolean isBlacklisted(String token) {
|
||||
return blacklist.containsKey(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务,定期清理黑名单中已过期的令牌。
|
||||
* cron 表达式 "0 0 * * * *" 表示每小时的 0 分 0 秒执行一次。
|
||||
*/
|
||||
@Scheduled(cron = "*/30 * * * * *")
|
||||
public void cleanupExpiredTokens() {
|
||||
logger.info("开始清理黑名单中的过期令牌... 当前黑名单大小:{}", blacklist.size());
|
||||
|
||||
// 使用 removeIf 安全地从 ConcurrentHashMap 中移除过期的条目
|
||||
blacklist.entrySet().removeIf(entry -> entry.getValue().before(new Date()));
|
||||
|
||||
logger.info("清理完成。当前黑名单大小:{}", blacklist.size());
|
||||
}
|
||||
}
|
||||
|
@ -61,4 +61,14 @@ public class JwtTokenProvider {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 新增:从 JWT 中获取过期时间
|
||||
public Date getExpirationDateFromToken(String token) {
|
||||
Claims claims = Jwts.parserBuilder()
|
||||
.setSigningKey(key)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
return claims.getExpiration();
|
||||
}
|
||||
}
|
@ -27,4 +27,4 @@ spring.jpa.properties.hibernate.format_sql=true
|
||||
# 用于签发 JWT 的密钥。请务必修改为一个足够长且复杂的字符串,不要在生产环境中泄露
|
||||
app.jwt.secret=YourSuperSecretKeyForJWTsWhichIsLongAndSecureAbcdAbcdAbcdAbcdAbcdAbcdAbcdAbcdAbcdAbcd
|
||||
# JWT 的过期时间(毫秒),这里设置为 1 小时
|
||||
app.jwt.expiration-ms=3600000
|
||||
app.jwt.expiration-ms=60000
|
||||
|
@ -20,9 +20,9 @@ Content-Type: application/json
|
||||
|
||||
### Get user info
|
||||
GET http://localhost:8080/api/user/me
|
||||
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAyIiwiaWF0IjoxNzQ5MTk2ODQxLCJleHAiOjE3NDkyMDA0NDF9.BM9ZeCP8Xbesk8hQj04Rr4EMRQ84fpjX9ikk8yIUPvF0mS5pVoR5J_bEJ1It5C6UkFteq0v8VVK9nWHDMfIEGg
|
||||
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAyIiwiaWF0IjoxNzQ5MTk3NzEzLCJleHAiOjE3NDkxOTc3NzN9.34iPSN77CJ2yrOp9pxCBguNkEJqu8VTgrIb7oWPQh1yTQQVcHMxQuMlMolorUOT216BF0_7b9vWS_COONQzGQA
|
||||
|
||||
### Logout
|
||||
POST http://localhost:8080/api/auth/logout
|
||||
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAyIiwiaWF0IjoxNzQ5MTk2ODQxLCJleHAiOjE3NDkyMDA0NDF9.BM9ZeCP8Xbesk8hQj04Rr4EMRQ84fpjX9ikk8yIUPvF0mS5pVoR5J_bEJ1It5C6UkFteq0v8VVK9nWHDMfIEGg
|
||||
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAyIiwiaWF0IjoxNzQ5MTk3NzEzLCJleHAiOjE3NDkxOTc3NzN9.34iPSN77CJ2yrOp9pxCBguNkEJqu8VTgrIb7oWPQh1yTQQVcHMxQuMlMolorUOT216BF0_7b9vWS_COONQzGQA
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user