令牌生成与验证流程:对称加密与非对称加密的令牌设计
聊完了令牌化接口的基础概念,接下来咱们得深入一点。
令牌到底是怎么生成的?又是怎么验证的?
这里头有两个核心流派:对称加密和非对称加密。
很多新人觉得这俩就是选A还是选B的问题。其实不然。我个人的经验是,选哪个,取决于你的业务场景和信任边界。选错了,要么性能崩盘,要么安全漏风。
1. 令牌的生命周期,先看全貌
在讨论加密方式之前,我们先搞清楚令牌从生到死经历了什么。
令牌核心流程: 颁发 → 传输 → 验证 → 使用 → 刷新 → 撤销
这里面,生成和验证是最关键的两个环节,也是我们今天要拆解的重点。
我建议你先看下面这张图,把整体脉络捋一遍。
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,哪怕慢一点,也再没出过类似问题。
好了,对称与非对称的令牌设计你心里应该有数了。下个环节,我们会聊聊令牌的存储与传输优化——也就是让你的令牌在实际跑起来的时候,又快又省带宽。