java實(shí)現(xiàn)認(rèn)證與授權(quán)的jwt與token+redis,哪種方案更好用?
JWT(JSON Web Token)與Token+Redis是兩種常見(jiàn)的用戶認(rèn)證方案,它們?cè)谠O(shè)計(jì)原理、性能和安全特性上存在顯著差異。JWT為無(wú)狀態(tài)認(rèn)證,適合分布式系統(tǒng)但無(wú)法主動(dòng)失效;Token+Redis依賴(lài)Redis存儲(chǔ)會(huì)話,支持實(shí)時(shí)吊銷(xiāo)但運(yùn)維復(fù)雜,兩者各有優(yōu)劣,混合方案結(jié)合短期JWT與Redis黑名單實(shí)現(xiàn)安全與便利平衡,推薦根據(jù)業(yè)務(wù)場(chǎng)景靈活選擇。
一、認(rèn)證與授權(quán)
在深入討論之前,我們先明確兩個(gè)基本概念:
- 認(rèn)證(Authentication):你是誰(shuí)?驗(yàn)證用戶身份的過(guò)程
- 授權(quán)(Authorization):你能做什么?驗(yàn)證用戶權(quán)限的過(guò)程
無(wú)論是JWT還是Token+Redis,都是用來(lái)解決這兩個(gè)問(wèn)題的技術(shù)方案。

二、JWT方案
2.1 JWT是什么?
JWT是一種無(wú)狀態(tài)的身份驗(yàn)證機(jī)制,通過(guò)將用戶信息編碼在令牌中實(shí)現(xiàn)驗(yàn)證。其核心優(yōu)勢(shì)在于分布式友好和性能高,適合微服務(wù)架構(gòu)和跨域SSO場(chǎng)景。但由于無(wú)法主動(dòng)失效Token,存在信息泄露風(fēng)險(xiǎn),且權(quán)限更新需要重新生成Token。
JWT(JSON Web Token)是一種開(kāi)放標(biāo)準(zhǔn)(RFC 7519),用于在各方之間安全地傳輸信息作為JSON對(duì)象。JWT由三部分組成:
header.payload.signature
- Header:包含令牌類(lèi)型和簽名算法
- Payload:包含聲明(用戶信息、過(guò)期時(shí)間等)
- Signature:用于驗(yàn)證消息在傳輸過(guò)程中沒(méi)有被篡改
2.2 JWT的工作流程
讓我們通過(guò)一個(gè)完整的登錄流程來(lái)理解JWT的工作原理:

2.3 JWT的Java實(shí)現(xiàn)示例
下面是一個(gè)簡(jiǎn)單的JWT工具類(lèi)實(shí)現(xiàn):
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
public class JwtUtil {
// 密鑰,實(shí)際項(xiàng)目中應(yīng)從配置中讀取
private static final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
// 過(guò)期時(shí)間:2小時(shí)
private static final long EXPIRATION_TIME = 2 * 60 * 60 * 1000;
/**
* 生成JWT
*/
public static String generateToken(String userId, String username, List<String> roles) {
return Jwts.builder()
.setSubject(userId)
.claim("username", username)
.claim("roles", roles)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(key)
.compact();
}
/**
* 驗(yàn)證并解析JWT
*/
public static Claims parseToken(String token) {
try {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
} catch (ExpiredJwtException e) {
thrownew RuntimeException("Token已過(guò)期", e);
} catch (JwtException e) {
thrownew RuntimeException("Token無(wú)效", e);
}
}
/**
* 刷新Token
*/
public static String refreshToken(String token) {
Claims claims = parseToken(token);
return generateToken(claims.getSubject(),
claims.get("username", String.class),
claims.get("roles", List.class));
}
}2.4 JWT的優(yōu)點(diǎn)和缺點(diǎn)
優(yōu)點(diǎn):
- 無(wú)狀態(tài):服務(wù)端不需要存儲(chǔ)會(huì)話信息
- 跨域友好:適合分布式系統(tǒng)和微服務(wù)架構(gòu)
- 自包含:令牌中包含所有必要信息
- 擴(kuò)展性好:可以輕松添加自定義聲明
缺點(diǎn):
- 無(wú)法主動(dòng)失效:一旦簽發(fā),在到期前一直有效
- 令牌大小:包含的信息越多,令牌越大
- 安全性依賴(lài):完全依賴(lài)簽名,密鑰泄露后果嚴(yán)重
三、Token+Redis方案
3.1 Token+Redis是什么?
該方案通過(guò)Redis集中存儲(chǔ)會(huì)話信息,具有完全控制會(huì)話和動(dòng)態(tài)權(quán)限管理的優(yōu)勢(shì),可實(shí)時(shí)吊銷(xiāo)Token或綁定設(shè)備屬性增強(qiáng)安全性。但性能依賴(lài)Redis集群,運(yùn)維復(fù)雜度較高。實(shí)現(xiàn)時(shí)通常將生成的Token存入Redis并設(shè)置過(guò)期時(shí)間,結(jié)合攔截器進(jìn)行雙重驗(yàn)證(簽名校驗(yàn)和Redis查詢(xún))。
Token+Redis方案使用隨機(jī)生成的令牌作為用戶會(huì)話的標(biāo)識(shí),將會(huì)話數(shù)據(jù)存儲(chǔ)在Redis中。
這種方案本質(zhì)上是有狀態(tài)的,服務(wù)端需要維護(hù)會(huì)話狀態(tài)。
3.2 Token+Redis的工作流程

3.3 Token+Redis的Java實(shí)現(xiàn)示例
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Component
public class RedisSessionManager {
private final RedisTemplate<String, Object> redisTemplate;
// 會(huì)話過(guò)期時(shí)間:2小時(shí)
private static final long SESSION_EXPIRE_TIME = 2 * 60 * 60;
public RedisSessionManager(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 創(chuàng)建會(huì)話
*/
public String createSession(User user) {
String token = generateToken();
SessionInfo sessionInfo = new SessionInfo(user.getId(), user.getUsername(), user.getRoles());
redisTemplate.opsForValue().set(
getRedisKey(token),
sessionInfo,
SESSION_EXPIRE_TIME,
TimeUnit.SECONDS
);
return token;
}
/**
* 獲取會(huì)話信息
*/
public SessionInfo getSession(String token) {
return (SessionInfo) redisTemplate.opsForValue().get(getRedisKey(token));
}
/**
* 刪除會(huì)話
*/
public void deleteSession(String token) {
redisTemplate.delete(getRedisKey(token));
}
/**
* 刷新會(huì)話有效期
*/
public void refreshSession(String token) {
redisTemplate.expire(getRedisKey(token), SESSION_EXPIRE_TIME, TimeUnit.SECONDS);
}
/**
* 生成隨機(jī)token
*/
private String generateToken() {
return UUID.randomUUID().toString().replace("-", "");
}
/**
* 獲取Redis key
*/
private String getRedisKey(String token) {
return "session:" + token;
}
/**
* 會(huì)話信息類(lèi)
*/
@Data
@AllArgsConstructor
public static class SessionInfo {
private String userId;
private String username;
private List<String> roles;
private long createTime;
public SessionInfo(String userId, String username, List<String> roles) {
this.userId = userId;
this.username = username;
this.roles = roles;
this.createTime = System.currentTimeMillis();
}
}
}3.4 Token+Redis的優(yōu)點(diǎn)和缺點(diǎn)
優(yōu)點(diǎn):
- 主動(dòng)控制:可以隨時(shí)使特定令牌失效
- 信息量小:令牌只是一個(gè)標(biāo)識(shí)符,不會(huì)太大
- 靈活性高:可以存儲(chǔ)復(fù)雜的會(huì)話狀態(tài)
- 安全性好:令牌泄露可以立即撤銷(xiāo)
缺點(diǎn):
- 有狀態(tài):服務(wù)端需要存儲(chǔ)會(huì)話信息
- Redis依賴(lài):Redis成為單點(diǎn)故障源
- 網(wǎng)絡(luò)開(kāi)銷(xiāo):每次請(qǐng)求都需要查詢(xún)Redis
- 擴(kuò)展性挑戰(zhàn):需要處理Redis集群和數(shù)據(jù)同步
四、深度對(duì)比分析
4.1 性能對(duì)比
從性能角度,兩種方案有顯著差異:
方面 | JWT | Token+Redis |
認(rèn)證速度 | 快(本地驗(yàn)證) | 慢(需要Redis查詢(xún)) |
網(wǎng)絡(luò)開(kāi)銷(xiāo) | 小 | 大(每次請(qǐng)求都需要訪問(wèn)Redis) |
服務(wù)端壓力 | 小 | 大(Redis需要處理大量查詢(xún)) |
擴(kuò)展成本 | 低 | 高(需要維護(hù)Redis集群) |
4.2 安全性對(duì)比
安全性是認(rèn)證方案的核心考量因素:
JWT安全性考慮:
- 密鑰管理:簽名密鑰需要嚴(yán)格保護(hù),定期輪換
- 令牌泄露:無(wú)法主動(dòng)失效,只能等待自動(dòng)過(guò)期
- 算法選擇:需要選擇安全的簽名算法(如HS256、RS256)
Token+Redis安全性考慮:
- Redis安全:需要保證Redis實(shí)例的安全性
- 令牌隨機(jī)性:令牌必須足夠隨機(jī),防止猜測(cè)
- 傳輸安全:需要HTTPS防止令牌被竊聽(tīng)
4.3 適用場(chǎng)景對(duì)比
不同的業(yè)務(wù)場(chǎng)景適合不同的方案:
適合JWT的場(chǎng)景:
- 分布式系統(tǒng)和微服務(wù)架構(gòu)
- 需要跨域認(rèn)證的單頁(yè)應(yīng)用(SPA)
- 無(wú)狀態(tài)API服務(wù)
- 移動(dòng)應(yīng)用后端
適合Token+Redis的場(chǎng)景:
- 需要精細(xì)控制會(huì)話的企業(yè)應(yīng)用
- 需要實(shí)時(shí)吊銷(xiāo)權(quán)限的系統(tǒng)
- 會(huì)話信息復(fù)雜的傳統(tǒng)Web應(yīng)用
- 對(duì)安全性要求極高的金融系統(tǒng)
五、混合方案
有些小伙伴在工作中可能會(huì)想:能不能結(jié)合兩種方案的優(yōu)點(diǎn)?
答案是肯定的!
下面介紹一種混合方案:
5.1 短期JWT + Redis黑名單
這種方案使用短期有效的JWT,配合Redis黑名單實(shí)現(xiàn)主動(dòng)注銷(xiāo):
public class HybridAuthManager {
private final JwtUtil jwtUtil;
private final RedisTemplate<String, Object> redisTemplate;
// JWT短期有效期:15分鐘
private static final long SHORT_EXPIRATION = 15 * 60 * 1000;
// 刷新令牌有效期:7天
private static final long REFRESH_EXPIRATION = 7 * 24 * 60 * 60 * 1000;
/**
* 生成訪問(wèn)令牌和刷新令牌
*/
public AuthResponse generateTokenPair(User user) {
// 生成短期訪問(wèn)令牌
String accessToken = jwtUtil.generateToken(
user.getId(), user.getUsername(), user.getRoles(), SHORT_EXPIRATION);
// 生成長(zhǎng)期刷新令牌
String refreshToken = UUID.randomUUID().toString();
// 存儲(chǔ)刷新令牌到Redis
storeRefreshToken(refreshToken, user.getId());
returnnew AuthResponse(accessToken, refreshToken);
}
/**
* 刷新訪問(wèn)令牌
*/
public String refreshAccessToken(String refreshToken) {
// 驗(yàn)證刷新令牌有效性
String userId = validateRefreshToken(refreshToken);
if (userId == null) {
thrownew RuntimeException("刷新令牌無(wú)效");
}
// 獲取用戶信息
User user = userService.getUserById(userId);
// 生成新的訪問(wèn)令牌
return jwtUtil.generateToken(
user.getId(), user.getUsername(), user.getRoles(), SHORT_EXPIRATION);
}
/**
* 注銷(xiāo)令牌
*/
public void logout(String accessToken, String refreshToken) {
// 將訪問(wèn)令牌加入黑名單(剩余有效期內(nèi))
Claims claims = jwtUtil.parseToken(accessToken);
long expiration = claims.getExpiration().getTime() - System.currentTimeMillis();
if (expiration > 0) {
redisTemplate.opsForValue().set(
"blacklist:" + accessToken,
"logout",
expiration,
TimeUnit.MILLISECONDS
);
}
// 刪除刷新令牌
if (refreshToken != null) {
redisTemplate.delete("refresh_token:" + refreshToken);
}
}
/**
* 驗(yàn)證令牌是否在黑名單中
*/
public boolean isTokenBlacklisted(String token) {
return redisTemplate.hasKey("blacklist:" + token);
}
}5.2 混合方案工作流程

六、實(shí)際項(xiàng)目選型建議
根據(jù)我多年的工作經(jīng)驗(yàn),給大家一些實(shí)用的選型建議:
6.1 選擇JWT當(dāng)以下情況成立時(shí):
- 系統(tǒng)是分布式架構(gòu),需要無(wú)狀態(tài)認(rèn)證。
- 需要支持跨域認(rèn)證(如多個(gè)前端應(yīng)用共享后端)。
- API消費(fèi)者主要是第三方應(yīng)用或移動(dòng)端。
- 團(tuán)隊(duì)有能力管理好密鑰和令牌安全。
6.2 選擇Token+Redis當(dāng)以下情況成立時(shí):
- 系統(tǒng)是單體或少量服務(wù)的架構(gòu)。
- 需要精細(xì)的會(huì)話控制和實(shí)時(shí)權(quán)限管理。
- 有專(zhuān)業(yè)的運(yùn)維團(tuán)隊(duì)維護(hù)Redis集群。
- 對(duì)安全性要求極高,需要即時(shí)吊銷(xiāo)能力。
6.3 選擇混合方案當(dāng)以下情況成立時(shí):
- 既需要JWT的無(wú)狀態(tài)特性,又需要主動(dòng)注銷(xiāo)能力。
- 系統(tǒng)對(duì)用戶體驗(yàn)要求高(避免頻繁登錄)。
- 有能力處理稍復(fù)雜的令牌管理邏輯。
- 需要平衡安全性和便利性。
總結(jié)
通過(guò)上面的詳細(xì)分析,JWT和token+redis這兩種方案,各有優(yōu)缺點(diǎn)和適用場(chǎng)景。
我們可以得出以下結(jié)論:
- 沒(méi)有絕對(duì)的最好方案:只有最適合具體業(yè)務(wù)場(chǎng)景的方案。
- JWT優(yōu)勢(shì)在無(wú)狀態(tài)和擴(kuò)展性:適合分布式系統(tǒng)和API優(yōu)先的架構(gòu)。
- Token+Redis優(yōu)勢(shì)在控制和靈活性:適合需要精細(xì)會(huì)話管理的企業(yè)應(yīng)用。
- 混合方案取長(zhǎng)補(bǔ)短:適合大多數(shù)現(xiàn)代Web應(yīng)用。
有些小伙伴在工作中可能會(huì)盲目追求技術(shù)的新穎性,或者過(guò)度設(shè)計(jì)認(rèn)證方案。
我的建議是:從實(shí)際業(yè)務(wù)需求出發(fā),選擇最簡(jiǎn)單可靠的方案。
對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō),我推薦采用混合方案:
- 使用短期JWT保證API的無(wú)狀態(tài)特性。
- 使用刷新令牌機(jī)制優(yōu)化用戶體驗(yàn)。
- 使用Redis黑名單提供主動(dòng)注銷(xiāo)能力。
- 使用HTTPS和嚴(yán)格的密鑰管理保證安全性。
無(wú)論選擇哪種方案,都要記住:安全不是一個(gè)功能,而是一個(gè)過(guò)程。
到此這篇關(guān)于java實(shí)現(xiàn)認(rèn)證與授權(quán)的jwt與token+redis,哪種方案更好用?的文章就介紹到這了,更多相關(guān)java實(shí)現(xiàn)認(rèn)證與授權(quán)的jwt與token+redis內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring對(duì)象創(chuàng)建范式的五大適用場(chǎng)景詳解
本文深度解析了Spring中依賴(lài)注入與直接實(shí)例化的決策邊界,破除“萬(wàn)物皆Bean”誤區(qū),文章系統(tǒng)梳理了五大適合直接new的場(chǎng)景,希望對(duì)大家有所幫助2026-06-06
Java實(shí)現(xiàn)八種排序算法詳細(xì)代碼舉例
排序問(wèn)題一直是程序員工作與面試的重點(diǎn),今天特意整理研究下與大家共勉!這篇文章主要介紹了Java實(shí)現(xiàn)八種排序算法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-10-10
JAVA實(shí)現(xiàn)簡(jiǎn)單系統(tǒng)登陸注冊(cè)模塊
這篇文章主要介紹了一個(gè)簡(jiǎn)單完整的登陸注冊(cè)模塊的實(shí)現(xiàn)過(guò)程,文章條理清晰,在實(shí)現(xiàn)過(guò)程中加深了對(duì)相關(guān)概念的理解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-07-07
Spring Security 安全認(rèn)證的示例代碼
這篇文章主要介紹了Spring Security 安全認(rèn)證的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10

