通過Redis實(shí)現(xiàn)Token黑名單機(jī)制的具體方案
1. 概述
如果沒有為Token提供主動(dòng)失效機(jī)制。一旦Token被簽發(fā),在過期之前將一直有效,存在以下安全隱患:
- 無法主動(dòng)注銷:用戶注銷后,已簽發(fā)的Token仍然有效
- 安全風(fēng)險(xiǎn):Token泄露后無法立即失效
- 缺乏控制:無法對特定Token進(jìn)行精準(zhǔn)控制
本博客通過將已失效的Token存儲(chǔ)在Redis中,可以確保Token在被主動(dòng)注銷后無法繼續(xù)使用,提高了系統(tǒng)的安全性和可控性。
2. 具體方案
2.1 設(shè)計(jì)思路
通過在Redis中維護(hù)一個(gè)Token黑名單來實(shí)現(xiàn)Token的主動(dòng)失效功能:
- 當(dāng)用戶注銷或Token需要主動(dòng)失效時(shí),將Token加入黑名單
- 在驗(yàn)證Token時(shí),先檢查是否在黑名單中
- 如果在黑名單中,則認(rèn)為Token已失效
2.2 Redis存儲(chǔ)設(shè)計(jì)
Key: token:blacklist:{token}
Value: "blacklisted"
Expire: Token剩余有效時(shí)間
2.3 TokenUtil中新增方法
2.3.1 addToBlacklist方法
/**
* 將Token加入黑名單,實(shí)現(xiàn)主動(dòng)失效
*
* @param token JWT token
* @return 是否成功加入黑名單
*/
public boolean addToBlacklist(String token) {
try {
// 獲取Token的過期時(shí)間
Date expirationDate = getExpirationDateFromToken(token);
if (expirationDate == null) {
return false;
}
// 計(jì)算剩余有效時(shí)間
long remainingTime = expirationDate.getTime() - System.currentTimeMillis();
if (remainingTime <= 0) {
return false;
}
// 將Token加入Redis黑名單,設(shè)置過期時(shí)間為Token剩余有效時(shí)間
String key = TOKEN_BLACKLIST_PREFIX + token;
return redisUtil.set(key, "blacklisted", remainingTime / 1000);
} catch (Exception e) {
return false;
}
}
2.3.2 isTokenInBlacklist方法
/**
* 檢查Token是否在黑名單中
*
* @param token JWT token
* @return 是否在黑名單中
*/
public boolean isTokenInBlacklist(String token) {
String key = TOKEN_BLACKLIST_PREFIX + token;
return redisUtil.exists(key);
}
2.3.3 removeFromBlacklist方法
/**
* 從黑名單中移除Token
*
* @param token JWT token
* @return 是否成功移除
*/
public boolean removeFromBlacklist(String token) {
String key = TOKEN_BLACKLIST_PREFIX + token;
return redisUtil.del(key) > 0;
}
2.3.4 修改validateToken方法
/**
* 驗(yàn)證Token是否合法且未過期
*
* @param token JWT token
* * @return 是否有效
*/
public Boolean validateToken(String token) {
try {
// 檢查Token是否在黑名單中
if (isTokenInBlacklist(token)) {
return false;
}
JwtParser parser = Jwts.parser().verifyWith(secretKey).build();
parser.parseSignedClaims(token);
return true;
} catch (JwtException e) {
System.out.println("JWT exception: " + e.getMessage());
} catch (IllegalArgumentException e) {
System.out.println("JWT claims string is empty: " + e.getMessage());
}
return false;
}
3. 使用示例
3.1 用戶注銷時(shí)將Token加入黑名單
@PostMapping("/logout")
public ResultBean<String> logout(@RequestHeader("Authorization") String token) {
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
// 將Token加入黑名單
boolean added = tokenUtil.addToBlacklist(token);
if (added) {
return ResultBean.success("注銷成功");
}
}
return ResultBean.error("注銷失敗");
}
3.2 在攔截器中驗(yàn)證Token
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
private TokenUtil tokenUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
// 驗(yàn)證Token(會(huì)自動(dòng)檢查黑名單)
if (!tokenUtil.validateToken(token)) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
}
return true;
}
}
3.3 管理員強(qiáng)制用戶下線
@PostMapping("/admin/forceLogout")
public ResultBean<String> forceLogout(@RequestParam String token) {
// 將Token加入黑名單
boolean added = tokenUtil.addToBlacklist(token);
if (added) {
return ResultBean.success("用戶已強(qiáng)制下線");
}
return ResultBean.error("操作失敗");
}
4. 優(yōu)化效果
4.1 安全性提升
- 實(shí)現(xiàn)了Token的主動(dòng)失效功能
- 可以精準(zhǔn)控制特定Token的可用性
- 有效防止Token泄露后的安全風(fēng)險(xiǎn)
4.2 控制性增強(qiáng)
- 提供了細(xì)粒度的Token控制能力
- 支持用戶主動(dòng)注銷和管理員強(qiáng)制下線
- 可以根據(jù)業(yè)務(wù)需求靈活控制Token生命周期
4.3 用戶體驗(yàn)改善
- 用戶注銷后Token立即失效
- 管理員可以強(qiáng)制用戶下線
- 提高了系統(tǒng)的安全性和可控性
5. 注意事項(xiàng)
- Redis性能: 黑名單存儲(chǔ)在Redis中,需要注意Redis的性能和容量
- 過期時(shí)間: 黑名單中的Token會(huì)自動(dòng)過期,過期時(shí)間與Token剩余有效時(shí)間一致
- 異常處理: 需要妥善處理Redis操作可能出現(xiàn)的異常
- 并發(fā)控制: 在高并發(fā)場景下需要注意Redis操作的并發(fā)控制
以上就是通過Redis實(shí)現(xiàn)Token黑名單機(jī)制的具體方案的詳細(xì)內(nèi)容,更多關(guān)于Redis實(shí)現(xiàn)Token黑名單機(jī)制的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Redis消息隊(duì)列的三種實(shí)現(xiàn)方式
本文主要介紹了Redis消息隊(duì)列的三種實(shí)現(xiàn)方式,主要包括List實(shí)現(xiàn)消息隊(duì)列,PubSub消息隊(duì)列,Stream消息隊(duì)列,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12
Redis集群節(jié)點(diǎn)通信過程/原理流程分析
這篇文章主要介紹了Redis集群節(jié)點(diǎn)通信過程/原理,詳細(xì)介紹了Cluster(集群)的節(jié)點(diǎn)通信的流程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
redis 限制內(nèi)存使用大小的實(shí)現(xiàn)
這篇文章主要介紹了redis 限制內(nèi)存使用大小的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
通過lua實(shí)現(xiàn)redis 分布式鎖的項(xiàng)目實(shí)踐
在Redis中使用Lua腳本實(shí)現(xiàn)分布式鎖 是一種高效、原子、安全的方式,本文就來介紹一下通過lua實(shí)現(xiàn)redis分布式鎖,具有一定的參考價(jià)值,感興趣的可以了解一下2026-02-02
在Windows系統(tǒng)上部署Redis的多種解決方案
本文詳細(xì)介紹了在Windows上部署Redis的方法,包括選擇版本與資源、環(huán)境準(zhǔn)備、核心部署實(shí)戰(zhàn)、核心配置文件詳解、遠(yuǎn)程連接與防火墻設(shè)置等內(nèi)容,文章還推薦了幾款適合的可視化客戶端,并簡要介紹了替代部署方案,需要的朋友可以參考下2026-05-05
深入剖析 Redis 的三種集群方式以及實(shí)戰(zhàn)配置
本文深入解析Redis三種集群部署方式,文章包含完整的配置示例和操作指南,為Redis集群部署提供實(shí)用參考,感興趣的朋友跟隨小編一起看看吧2026-03-03
巧用Redis實(shí)現(xiàn)分布式鎖詳細(xì)介紹
大家好,本篇文章主要講的是巧用Redis實(shí)現(xiàn)分布式鎖詳細(xì)介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12

