微服务中Token鉴权除了用JWT之外,还有什么方案?

苏三 2025-09-17 10:17:13

前言

 

最近有读者问我:微服务中Token鉴权除了使用JWT之外,还有什么其他的方案?

 

今天这篇文章跟大家一起聊聊微服务Token鉴权的7种方案,希望对会有所帮助。

 

一、什么必须做Token鉴权?

 

传统Session的致命缺陷:

 

 

多个服务无法共享Session。

 

重复认证,导致系统性能严重下降。

 

2023年某电商平台发送安全事故:

 

  •  
  •  
GET /api/users/balance HTTP/1.1Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.Gfx6VO9tcxwk6xqx9yYzSfebbeKDTHkQKh0xhu4nJE0

 

黑客通过XSS攻击窃取此Token后,在2小时内盗取5万用户余额,暴露三大漏洞:

 

  • Token未绑定IP/设备指纹

  • 敏感操作未二次认证

  • 无异常行为检测机制

 

二、常见的Token鉴权方案

 

 
方案1:基础JWT+Redis方案

 

该方案适合初创系统。

 

核心架构:

 

 

致命陷阱:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
// 错误示例:未校验Token有效性public Claims parseJwt(String token) {    return Jwts.parser()         .setSigningKey(SECRET_KEY)        .parseClaimsJws(token)        .getBody(); // 若Token被注销仍能解析通过!}

 

正确实现:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
// 结合Redis校验Token状态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万的中小型系统

 

 
方案2:OAuth2.0授权框架

 

该方案是第三方接入的首选。

 

OAuth2.0包含了4种授权模式:

 

 

授权码模式流程:

 

 

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

 

关键点:必须使用PKCE扩展防止授权码截持攻击

 

 
方案3:Sa-Token轻量级框架

 

该方案是的国产Token鉴权方案的精品。

 

三大核心优势:

 

1、一行代码实现登录鉴权

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
// 登录StpUtil.login(10001); // 鉴权@SaCheckPermission("user:delete")public void deleteUser(Long id) {  // 业务代码}

 

2、内置会话管理

 

  •  
  •  
// 查询所有会话List<String> sessionList = StpUtil.searchSessionId("user:*"010);

 

3、踢人下线机制

 

  •  
  •  
  •  
  •  
  •  
// 根据账号ID踢人StpUtil.kickout(10001);
// 根据Token值踢人StpUtil.kickoutByTokenValue("xxxx");

 

网关集成方案:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
@Beanpublic SaReactorFilter saReactorFilter() {    return new SaReactorFilter()        .addInclude("/**")        .setAuth(obj -> {            SaRouter.match("/user/**").check(r -> StpUtil.checkPermission("USER"));            SaRouter.match("/admin/**").check(r -> StpUtil.checkPermission("ADMIN"));        });}

 

性能实测:QPS 12,000(Redis集群模式)

 

 
方案4:API网关统一鉴权

 

该方案是微服务的标配。

 

架构设计:

 

 

响应式鉴权过滤器:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
public class AuthFilter implements GlobalFilter {    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {        // 1. 提取Token        String token = extractToken(exchange.getRequest());                // 2. 响应式鉴权调用        return reactiveAuthService.validateToken(token)                .flatMap(valid -> {                    if (!valid) {                        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);                        return exchange.getResponse().setComplete();                    }                    return chain.filter(exchange);                });    }}

 

性能优化技巧:

 

  • 本地缓存:使用Caffeine缓存验证结果

  • 批量验证:聚合10ms内请求统一鉴权

  • 热点Token特殊处理

 

 
方案5:Token中继模式

 

该方案适合服务链调用。

 

核心问题:服务A调用服务B时Token如何传递

 

解决方案:

 

 

Feign中继实现:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
@FeignClient(name = "service-b")public interface ServiceBClient {        @GetMapping("/data")    Data getData(@RequestHeader("Authorization") String token);}
// 调用方public Data getData(String token) {    // 原样传递Token    return serviceBClient.getData("Bearer " + token); }

 

安全加固:使用JWT嵌套加密防止内部Token泄露

 

 
方案6:JWE加密令牌

 

该方案能保证金融级安全。

 

与JWT的核心区别:

 

 

Java生成示例:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
public String createJwe(User user) throws JOSEException {    // 1. 组装Header    JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.A256GCMKW,             EncryptionMethod.A256GCM).build();        // 2. 创建Payload    Payload payload = new Payload(new JSONObject()        .put("sub", user.getId())        .put("ssn", encrypt(user.getSsn()))); // 敏感信息加密        // 3. 加密Token    JWEObject jwe = new JWEObject(header, payload);    jwe.encrypt(new AESEncrypter(SECRET_KEY.getBytes()));        return jwe.serialize();}

 

适用场景:

 

  • 支付凭证

  • 身份证号传输

  • 医疗健康数据

 

 
方案7:双向TLS认证

 

该方案是零信任架构。

 

工作流程:

 

 

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

 

适用场景:

 

  • 服务网格内部通信

  • 银行核心系统

  • 政府机密数据交换

 

三、性能压测对比

 

方案
平均延时
CPU消耗
安全等级
适用场景
基础JWT
3ms
15%
★★☆
内部微服务
OAuth2.0
35ms
40%
★★★☆
第三方开放平台
Sa-Token
5ms
18%
★★★
快速开发项目
网关统一鉴权
8ms
25%
★★★☆
多语言混合架构
Token中继
12ms
30%
★★★
服务链调用
JWE加密
45ms
60%
★★★★☆
金融敏感数据
mTLS
20ms
50%
★★★★★
零信任网络

 

测试环境:AWS c5.4xlarge 16核32GB × 3节点

 

四、安全攻防

 

 
1、四大攻击手段及防御

 

攻击类型 防御方案 代码实现
Token窃取
绑定设备指纹
StpUtil.getToken().setExtra("deviceId", fingerprint)
重放攻击
Nonce校验+时间戳
redis.opsForValue().setIfAbsent(nonce, "used", 5, TimeUnit.SECONDS)
越权访问
动态权限校验
@SaCheckPermission("#user.id")
Token破解
定期轮换签名密钥
Jwts.parserBuilder().setSigningKeyResolver(new KeyRotationResolver())

 

 
2、审计日志必备字段

 

为了保证系统的操作安全,我们需要增加审计日志表。

 

审计日志必备字段如下:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
public class AuditLog {    private String tokenId;      // Token唯一标识    private String userId;       // 用户ID    private String operation;    // 操作类型    private String resource;     // 访问资源    private String clientIp;     // 客户端IP    private String deviceInfo;   // 设备信息    private LocalDateTime time;  // 操作时间}

 

五、方案如何选型?

 

 

总结

 

  • 初创期:基础JWT+Redis方案

  • 发展期:OAuth2.0+网关鉴权

  • 成熟期:JWE加密+双向TLS

  • 高级期:零信任架构+AI风控

 

微服务安全如同城堡防御——

单一的护城河无法阻挡所有入侵,

需要城墙、箭塔、卫兵的多层防护。

没有绝对安全的系统,只有不断提高的攻击成本。

 

作者丨苏三
来源丨公众号:苏三说技术(ID:susanSayJava)
dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn
最新评论
访客 2024年04月08日

如果字段的最大可能长度超过255字节,那么长度值可能…

访客 2024年03月04日

只能说作者太用心了,优秀

访客 2024年02月23日

感谢详解

访客 2024年02月20日

一般干个7-8年(即30岁左右),能做到年入40w-50w;有…

访客 2023年08月20日

230721

活动预告