Rpc鉴权授权策略
一、说明
鉴权授权策略,用于控制RPC请求的访问权限。是现代api-server的系统最重要的功能之一。
一般的鉴权授权策略可以分为2个大类:
- 基于会话
- 基于Token
而基于Token的鉴权授权策略又分为2大类:
- 基于随机字符串的Token
- 基于结构化的Token(例如:JWT)
二、基于会话的鉴权授权策略
基于会话的鉴权授权策略,一般是只应用于面向连接的通信。一般的这种通信具有持久化的特性,并且是有状态的。
三、基于Token的鉴权授权策略
基于Token的鉴权授权策略,一般用于面向消息的通信。
3.1 基于随机字符串的Token
3.2 基于结构化的Token(例如:JWT)
四、鉴权授权策略的比较
好的,我们来详细比较一下随机字符串(通常指无结构会话令牌)和 JWT(JSON Web Token)的优缺点以及适用场景。
核心区别:
- 随机字符串 (无结构令牌): 本质上就是一个不可预测的长字符串(如
f8a3d7c0b1e9
)。它本身不包含任何有意义的信息,只是一个指向服务器端存储(通常是数据库或缓存)中会话数据的引用。 - JWT (结构化令牌): 是一个经过数字签名或加密的、自包含的结构化字符串。它由三部分组成(Header.Payload.Signature),其中
Payload
部分包含了声明(通常是关于用户身份和权限的 JSON 对象)。服务器可以验证其签名/加密,并直接从中提取信息,无需查询后端存储(至少在有效期内)。
4.1 随机字符串 (无结构会话令牌)
-
优点:
- 简单轻量: 生成和验证极其简单快速(生成随机数 -> 存储;收到请求 -> 查存储)。
- 完全控制: 服务器拥有绝对控制权。可以即时撤销(删除存储条目)、修改关联数据(更新存储条目)或强制过期。
- 无信息泄露: 令牌本身不包含任何用户或会话信息,即使被截获,攻击者也无法从中直接获取有效内容(前提是字符串本身足够随机)。
- 存储开销可控: 服务器端存储的大小和内容完全由应用决定。
- 天然防篡改: 篡改令牌会导致在服务器端存储中查找失败,验证直接不通过。
-
缺点:
- 状态性: 服务器必须维护一个存储(数据库、Redis 等)来关联令牌和实际的会话数据。这引入了状态。
- 数据库/缓存依赖: 每次验证令牌都需要查询后端存储。在高并发场景下,这可能成为性能瓶颈和单点故障。
- 扩展性挑战: 在分布式系统或微服务架构中,需要共享会话存储(例如集中式 Redis 集群)或实现粘性会话(Session Affinity),增加了复杂性和潜在瓶颈。
- 无内置信息: 令牌本身不携带任何信息,所有数据都需要从存储中获取。
-
典型使用场景:
- 传统的 Web 应用会话管理: 这是最经典的场景。用户登录后,服务器创建会话数据存储在服务端(内存、数据库、Redis),生成一个随机的 Session ID(通常存储在 Cookie 中)返回给浏览器。后续请求携带此 ID,服务器查询存储获取会话状态。
- 一次性令牌: 如密码重置令牌、邮箱验证令牌。它们通常是随机字符串,存储在数据库并关联特定操作和过期时间,使用一次即失效。
- 简单的 API 认证(较少见): 如果 API 调用频 率不高或架构简单,也可以使用类似机制(API Key + Secret,但 Secret 通常也需要存储和验证)。
- 需要即时撤销能力的场景: 如用户登出、管理员踢人下线等,需要立即使令牌失效的场景。
4.2 JWT (JSON Web Token)
-
优点:
- 无状态: 这是 JWT 最大的优势。服务器不需要在本地或共享存储中保存会话状态。验证仅依赖于签名(和可选的加密)以及预定义的密钥/证书。极大简化了服务器架构,消除了数据库查询瓶颈。
- 自包含: Payload 中可以携带有用的声明(用户名、用户ID、角色、权限、过期时间等)。验证通过后,服务器可以直接使用这些信息,无需额外查询。
- 扩展性极佳: 完美适应分布式系统和微服务架构。任何服务实例只要拥有验证签名/解密的密钥,都可以独立验证令牌并提取所需信息。天然支持跨域/跨服务认证。
- 性能(特定场景): 避免了每次请求的存储查询开销(验证签名的计算开销通常远小于网络 I/O 和数据库查询)。在分布式系统中,优势尤其明显。
- 标准化: 是 IETF 标准 (RFC 7519),有成熟的库支持多种语言,互操作性好。
-
缺点:
- 体积较大: 由于是 Base64 编码的 JSON,通常比随机字符串长很多。在带宽敏感或需频繁传输的场景(如放在 HTTP Header 中)可能成为负担。
- 难以主动撤销/失效: 一旦签发,在自然过期前,很难强制使其失效(因为服务端无状态)。实现主动撤销需要额外机制(如黑名单、短期有效期 + Refresh Token),增加了复杂性。
- 安全风险:
- 令牌泄露: 如果 JWT 被盗(如 XSS、中间人攻击),攻击者可以在有效期内冒充用户(“持票攻击”)。缩短有效期和使用 HTTPS 是必须的。
- 签名算法安全: 如果使用弱算法(如
HS256
密钥太弱)或实现不当(如未验证签名),可能被伪造。必须使用强算法(如RS256
,ES256
)并妥善保管私钥/密钥。 - 敏感数据泄露: Payload 默认是 Base64 编码(可逆),不应在其中存放密码、信用卡号等绝对敏感信息。如需保密,应使用 JWE(JSON Web Encryption)进行加密。
- 客户端存储责任: 令牌由客户端(浏览器、移动 App)存储和管理,需要防范 XSS、CSRF 等攻击。
- 实现复杂度: 需要正确理解和实现签名/验证、密钥管理、声明处理、过期处理等,比生成随机字符串更复杂。
-
典型使用场景:
- 跨域/单点登录: 用户在一个域登录后,可以获取一个 JWT,用于访问其他信任该 JWT 签发方的应用或服务。OAuth 2.0 / OpenID Connect 的核心令牌之一就是 JWT。
- API 认证与授权: 现代 RESTful / GraphQL API 的首选认证机制。客户端在登录后获取 JWT,后续请求在
Authorization: Bearer <token>
头中携带。API 服务器验证签名和声明即可判断身份和权限。 - 无状态微服务间通信: 微服务 A 可以将包含用户上下文的 JWT 传递给微服务 B ,B 能独立验证并使用其中的信息,无需调用中心化的认证服务或共享会话存储。
- 信息交换: 作为在双方之间安全传递声明信息的一种方式(需签名/加密确保完整性和保密性),例如在 OAuth 流程中传递用户信息(ID Token)。
4.3 总结与选择建议
特性 | 随机字符串 (无结构令牌) | JWT (JSON Web Token) |
---|---|---|
核心 | 引用 (指向服务器存储的数据) | 自包含 (数据在令牌内) |
状态 | 有状态 (服务器需存储会话) | 无状态 (服务器无需存储会话) |
信息携带 | 无 | 有 (Payload 中的声明) |
验证方式 | 查数据库/缓存 | 验证签名/解密 |
性能 | 每次请求需查存储 (可能成瓶颈) | 无存储查询 (签名验证计算开销小) |
扩展性 | 差 (需共享存储或粘性会话) | 极佳 (天 然支持分布式) |
撤销 | 容易 (直接删除存储条目) | 困难 (需额外机制如黑名单、短有效期+Refresh) |
大小 | 小 | 较大 |
安全性 | 依赖存储安全、传输安全;令牌本身无信息 | 依赖算法强度、密钥管理、传输安全;需防泄露、篡改 |
复杂度 | 低 (生成随机数、存、查) | 中高 (签名/验证、密钥管理、声明处理、安全最佳实践) |
典型场景 | 传统Web会话 一次性令牌 需即时撤销 | API 认证 单点登录 / SSO 微服务通信 |
如何选择?
-
选择随机字符串 (无结构令牌) 当:
- 你正在构建一个传统的、服务器端渲染的 Web 应用。
- 你需要立即且可靠地撤销令牌的能力(如用户登出)。
- 应用是单体或规模较小,维护共享会话存储不是问题。
- 令牌本身不需要携带额外的声明信息。
- 对性能要求极高且请求非常密集,且能承受存储查询开销(或有强大缓存)。
-
选择 JWT 当:
- 你在构建 API(尤其是 RESTful / GraphQL)。
- 你需要 SSO 或 跨域/跨服务认 证。
- 你的架构是 分布式、微服务,需要服务间传递用户上下文。
- 可扩展性 和 消除数据库依赖 是主要目标。
- 令牌需要携带一些非绝对敏感的声明(用户ID、角色、权限),并让服务端能直接使用。
- 你愿意并能够处理 JWT 的安全复杂性(签名、密钥管理、短有效期、HTTPS)和潜在的撤销难题。
重要安全提示:
- 无论使用哪种方式,都必须通过 HTTPS 传输令牌!
- JWT 的 Payload 不是加密的(除非使用 JWE),不要存敏感数据!
- 使用强随机数生成器创建随机字符串或 JWT 的
jti
(JWT ID)。 - 仔细选择并安全配置 JWT 的签名算法和密钥。
- 始终验证 JWT 的签名、有效期 (
exp
)、受众 (aud
) 等关键声明。 - 考虑令牌泄露的风险,使用较短的过期时间,并为 JWT 实现合理的撤销机制(如黑名单)或结合使用 Refresh Token。
在实践中,两者也并非完全互斥。例如,一个系统可能使用基于随机字符串的传统会话管理 Web 界面,而其后台 API 则使用 JWT 进行交互。或者,在 JWT 的流程中,Refresh Token 本身可能是一个存储在数据库中的随机字符串。理解各自的优缺点有助于你为系统的不同部分选择最合适的工具。