前言
最近有球友問我:微服務(wù)中Token鑒權(quán)除了使用JWT之外,還有什么其他的方案?
今天這篇文章跟大家一起聊聊微服務(wù)Token鑒權(quán)的7種方案,希望對會有所幫助。
1. 為什么必須做Token鑒權(quán)?
傳統(tǒng)Session的致命缺陷:

多個服務(wù)無法共享Session。
重復(fù)認(rèn)證,導(dǎo)致系統(tǒng)性能嚴(yán)重下降。
2023年某電商平臺發(fā)送安全事故:
GET /api/users/balance HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.Gfx6VO9tcxwk6xqx9yYzSfebbeKDTHkQKh0xhu4nJE0
黑客通過XSS攻擊竊取此Token后,在2小時內(nèi)盜取5萬用戶余額,暴露三大漏洞:
- Token未綁定IP/設(shè)備指紋
- 敏感操作未二次認(rèn)證
- 無異常行為檢測機(jī)制
2.常見的Token鑒權(quán)方案
方案1:基礎(chǔ)JWT+Redis方案
該方案適合初創(chuàng)系統(tǒng)。
核心架構(gòu):

致命陷阱:
public Claims parseJwt(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
正確實(shí)現(xiàn):
public boolean validateToken(String token, UserDetails details) {
String username = extractUsername(token);
String redisToken = redisTemplate.opsForValue().get("token:"+username);
return (username.equals(details.getUsername())
&& !isTokenExpired(token)
&& token.equals(redisToken);
}
適用場景:用戶量<100萬的中小型系統(tǒng)
方案2:OAuth2.0授權(quán)框架
該方案是第三方接入的首選。
OAuth2.0包含了4種授權(quán)模式:

授權(quán)碼模式流程:

Spring Boot配置示例:
spring:
security:
oauth2:
client:
registration:
github:
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_SECRET}
scope: user:email,read:user
provider:
github:
token-uri: https://github.com/login/oauth/access_token
user-info-uri: https://api.github.com/user
關(guān)鍵點(diǎn):必須使用PKCE擴(kuò)展防止授權(quán)碼截持攻擊
方案3:Sa-Token輕量級框架
該方案是的國產(chǎn)Token鑒權(quán)方案的精品。
三大核心優(yōu)勢:
- 一行代碼實(shí)現(xiàn)登錄鑒權(quán)
StpUtil.login(10001);
@SaCheckPermission("user:delete")
public void deleteUser(Long id) {
}
- 內(nèi)置會話管理
List<String> sessionList = StpUtil.searchSessionId("user:*", 0, 10);
- 踢人下線機(jī)制
StpUtil.kickout(10001);
StpUtil.kickoutByTokenValue("xxxx");
網(wǎng)關(guān)集成方案:
@Bean
public SaReactorFilter saReactorFilter() {
return new SaReactorFilter()
.addInclude("/**")
.setAuth(obj -> {
SaRouter.match("/user/**").check(r -> StpUtil.checkPermission("USER"));
SaRouter.match("/admin/**").check(r -> StpUtil.checkPermission("ADMIN"));
});
}
性能實(shí)測:QPS 12,000(Redis集群模式)
方案4:API網(wǎng)關(guān)統(tǒng)一鑒權(quán)
該方案是微服務(wù)的標(biāo)配。
架構(gòu)設(shè)計:

響應(yīng)式鑒權(quán)過濾器:
public class AuthFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = extractToken(exchange.getRequest());
return reactiveAuthService.validateToken(token)
.flatMap(valid -> {
if (!valid) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
});
}
}
性能優(yōu)化技巧:
- 本地緩存:使用Caffeine緩存驗證結(jié)果
- 批量驗證:聚合10ms內(nèi)請求統(tǒng)一鑒權(quán)
- 熱點(diǎn)Token特殊處理
方案5:Token中繼模式
該方案適合服務(wù)鏈調(diào)用。
核心問題:服務(wù)A調(diào)用服務(wù)B時Token如何傳遞
解決方案:

Feign中繼實(shí)現(xiàn):
@FeignClient(name = "service-b")
public interface ServiceBClient {
@GetMapping("/data")
Data getData(@RequestHeader("Authorization") String token);
}
public Data getData(String token) {
return serviceBClient.getData("Bearer " + token);
}
安全加固:使用JWT嵌套加密防止內(nèi)部Token泄露
方案6:JWE加密令牌
該方案能保證金融級安全。
與JWT的核心區(qū)別:

Java生成示例:
public String createJwe(User user) throws JOSEException {
JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.A256GCMKW,
EncryptionMethod.A256GCM).build();
Payload payload = new Payload(new JSONObject()
.put("sub", user.getId())
.put("ssn", encrypt(user.getSsn())));
JWEObject jwe = new JWEObject(header, payload);
jwe.encrypt(new AESEncrypter(SECRET_KEY.getBytes()));
return jwe.serialize();
}
適用場景:
- 支付憑證
- 身份證號傳輸
- 醫(yī)療健康數(shù)據(jù)
方案7:雙向TLS認(rèn)證
該方案是零信任架構(gòu)。
工作流程:

Spring Boot配置:
server:
ssl:
key-store: classpath:server-keystore.p12
key-store-password: changeit
key-alias: server
client-auth: need
trust-store: classpath:client-truststore.p12
trust-store-password: changeit
適用場景:
- 服務(wù)網(wǎng)格內(nèi)部通信
- 銀行核心系統(tǒng)
- 政府機(jī)密數(shù)據(jù)交換
3.性能壓測對比
方案 | 平均延時 | CPU消耗 | 安全等級 | 適用場景 |
---|
基礎(chǔ)JWT | 3ms | 15% | ★★☆ | 內(nèi)部微服務(wù) |
OAuth2.0 | 35ms | 40% | ★★★☆ | 第三方開放平臺 |
Sa-Token | 5ms | 18% | ★★★ | 快速開發(fā)項目 |
網(wǎng)關(guān)統(tǒng)一鑒權(quán) | 8ms | 25% | ★★★☆ | 多語言混合架構(gòu) |
Token中繼 | 12ms | 30% | ★★★ | 服務(wù)鏈調(diào)用 |
JWE加密 | 45ms | 60% | ★★★★☆ | 金融敏感數(shù)據(jù) |
mTLS | 20ms | 50% | ★★★★★ | 零信任網(wǎng)絡(luò) |
測試環(huán)境:AWS c5.4xlarge 16核32GB × 3節(jié)點(diǎn)
4.安全攻防
4.1 四大攻擊手段及防御
攻擊類型 | 防御方案 | 代碼實(shí)現(xiàn) |
---|
Token竊取 | 綁定設(shè)備指紋 | StpUtil.getToken().setExtra("deviceId", fingerprint) |
重放攻擊 | Nonce校驗+時間戳 | redis.opsForValue().setIfAbsent(nonce, "used", 5, TimeUnit.SECONDS) |
越權(quán)訪問 | 動態(tài)權(quán)限校驗 | @SaCheckPermission("#user.id") |
Token破解 | 定期輪換簽名密鑰 | Jwts.parserBuilder().setSigningKeyResolver(new KeyRotationResolver()) |
4.2 審計日志必備字段
為了保證系統(tǒng)的操作安全,我們需要增加審計日志表。
審計日志必備字段如下:
public class AuditLog {
private String tokenId;
private String userId;
private String operation;
private String resource;
private String clientIp;
private String deviceInfo;
private LocalDateTime time;
}
5.方案如何選型?

總結(jié)
- 初創(chuàng)期:基礎(chǔ)JWT+Redis方案
- 發(fā)展期:OAuth2.0+網(wǎng)關(guān)鑒權(quán)
- 成熟期:JWE加密+雙向TLS
- 高級期:零信任架構(gòu)+AI風(fēng)控
微服務(wù)安全如同城堡防御——
單一的護(hù)城河無法阻擋所有入侵,
需要城墻、箭塔、衛(wèi)兵的多層防護(hù)。
沒有絕對安全的系統(tǒng),只有不斷提高的攻擊成本。
轉(zhuǎn)自https://www.cnblogs.com/12lisu/p/19017202
該文章在 2025/8/4 8:50:39 編輯過