令牌生成与验证流程:对称加密与非对称加密的令牌设计

聊完了令牌化接口的基础概念,接下来咱们得深入一点。

令牌到底是怎么生成的?又是怎么验证的?

这里头有两个核心流派:对称加密和非对称加密。

很多新人觉得这俩就是选A还是选B的问题。其实不然。我个人的经验是,选哪个,取决于你的业务场景和信任边界。选错了,要么性能崩盘,要么安全漏风。

1. 令牌的生命周期,先看全貌

在讨论加密方式之前,我们先搞清楚令牌从生到死经历了什么。

令牌核心流程: 颁发 → 传输 → 验证 → 使用 → 刷新 → 撤销

这里面,生成和验证是最关键的两个环节,也是我们今天要拆解的重点。

我建议你先看下面这张图,把整体脉络捋一遍。

令牌生命周期与加密选择流程 客户端 令牌服务 验证服务 1. 申请令牌 2. 返回令牌 3. 携带令牌访问资源 对称加密令牌 RFC 7519 JWT + HS256 非对称加密令牌 RFC 7519 JWT + RS256 验证:使用共享密钥解码 + 验签 风险:密钥泄露则全盘皆输 验证:使用公钥解码 + 私钥验签 优点:公钥公开,私钥不落地
记住一个关键逻辑:生成令牌时用的密钥,验证时也必须配对。这是所有令牌签名方案的基础。

2. 对称加密令牌设计:HMAC + HS256

先说说对称加密。说白了,就是加密和解密用的是同一个密钥。

在令牌的世界里,最常用的对称算法是 HMAC-SHA256,也就是 JWT 里的 HS256。

2.1 它是怎么工作的?

我拿一个简单的例子说明。假设我们要生成一个访问令牌。

// 服务端有一个共享密钥
const SECRET_KEY = 'my-super-secret-key-2024';

// 定义令牌载荷(Payload)
const payload = {
  sub: 'user_123456',
  name: '张三',
  role: 'admin',
  exp: Math.floor(Date.now() / 1000) + 3600  // 1小时后过期
};

// 生成令牌:header.payload.signature
// 签名 = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), SECRET_KEY)

// 最终令牌(伪代码)
const  = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' +
              'eyJzdWIiOiJ1c2VyXzEyMzQ1NiIsIm5hbWUiOiLlvKDkuIkiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3MDAwMDAwMDB9.' +
              's5c3tY5kF6c8d1w3r4t7y9f0g2h4j6k8l0z2x4c6v8b9n0m2';

验证时,验证服务拿到令牌,用同一个密钥重新计算签名。如果算出来的签名和令牌里的签名一致,就通过。

我曾经踩过一个坑: 有一个项目把共享密钥写死了在代码里,结果密钥泄露后,攻击者可以签发任意身份的令牌。而且因为是对称的,你没法区分这个令牌是“我们自己签的”还是“攻击者签的”。
教训: HS256 要求密钥管理极其严格,不能硬编码,必须从安全的密钥服务(KMS)动态获取。

2.2 对称加密的优缺点

维度 说明
性能 极优。HMAC 计算速度极快,比非对称快 10-100 倍。
实现复杂度 低。只需要维护一个密钥库即可。
安全性 中等。密钥一旦泄露,所有令牌都可以被伪造。
适用场景 单体应用、微服务内部调用(服务之间信任度较高)。

我个人习惯: 在对延迟极其敏感的内部服务通信中,我会优先考虑 HS256。比如网关到后端服务的直连。但如果涉及跨组织的第三方集成,我会改用非对称加密。

3. 非对称加密令牌设计:RSA + RS256

再来看非对称加密。它用的是一对密钥:私钥签名,公钥验签。

3.1 它解决了什么问题?

对称加密最大的痛点是什么?密钥分发。你把共享密钥给了验证服务,验证服务就得保护好它。如果验证服务有几十上百个,密钥管理的风险指数级上升。

非对称加密就不一样了。私钥只存放在签发服务器,公钥可以公开给所有验证服务。公钥泄露了也没事,因为它没法用来签名。

// 生成密钥对(RSA 2048位)
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem

// 令牌签发(使用私钥)
const  = jwt.sign(payload, privateKey, { algorithm: 'RS256' });

// 令牌验证(使用公钥)
const decoded = jwt.verify(, publicKey, { algorithms: ['RS256'] });

验证流程也变了。服务端不再是一个“黑盒”,而是可以独立验证。

我见过不少团队做微服务时,每个服务都去调用中心认证服务验证令牌。这其实就是把验证延迟串行化了。
用 RS256 之后,每个服务本地缓存公钥,自己验签,延迟能降一个数量级。 这也是令牌化接口延迟优化的一个关键技巧。

3.2 非对称加密的优缺点

维度 说明
性能 较低。RSA 签名和验签速度都比 HMAC 慢,特别是签名阶段。
密钥管理 极优。私钥只需保护好一份,公钥随意分发。
安全性 高。即使验证服务被攻破,攻击者也无法伪造令牌。
适用场景 跨系统认证、第三方开放 API、OAuth 2.0 / OpenID Connect。

注意性能陷阱: 我之前优化过一个接口,发现每次请求验证令牌用了 15ms,其中 RSA 验签占了 12ms。后来用公钥缓存 + 批量验签优化,降到了 2ms。非对称不是银弹,你得接受它带来的计算开销。

4. 实战选择:什么时候用哪种?

一句话总结。

  • 用对称(HS256):你的所有服务都在同一个信任域里,你做主,密钥管理可控,且对性能有极致要求。
  • 用非对称(RS256/ES256):你需要把验证能力暴露给第三方,或者有多个不互信的服务需要独立验证。

如果还选不定,我个人建议:默认走非对称。虽然慢一点,但安全边际更高。性能问题可以通过缓存和硬件加速弥补,安全漏洞补起来可是要命的事。

避坑指南: 我曾经在某项目中,因为图省事全局用了 HS256,结果一个下游服务被拖库,共享密钥泄露。那周我几乎没睡觉,逐个通知所有合作方更换令牌。后来全部改成 RS256,哪怕慢一点,也再没出过类似问题。

好了,对称与非对称的令牌设计你心里应该有数了。下个环节,我们会聊聊令牌的存储与传输优化——也就是让你的令牌在实际跑起来的时候,又快又省带宽。