OAuth2.0/2.1授权简介与JWT对比
一、OAuth 2.0 核心概念与授权流程
OAuth 2.0 是 授权协议(非认证协议),核心目标是让第三方应用(客户端)在不获取用户账号密码的情况下,安全获取用户在资源服务器上的授权访问权限。
1. 核心角色
- 资源所有者(User):用户本人(如微信用户),拥有资源的访问权限。
- 客户端(Client):第三方应用(如小程序、APP),需要访问用户的资源。
- 授权服务器(Authorization Server):验证用户身份并颁发授权凭证(如 Token)的服务器(如微信开放平台)。
- 资源服务器(Resource Server):存储用户资源的服务器(如微信用户信息服务器),需验证 Token 合法性后提供资源。
2. 核心授权流程(通用四步)
OAuth 2.0 定义了多种授权模式(授权码模式、密码模式、客户端凭证模式、隐式模式),其中 授权码模式 是最安全、最常用的模式(适用于有后端的应用,如小程序+云开发/自建后端),流程如下:
客户端->>授权服务器: 1. 请求授权(携带客户端ID、回调地址、权限范围)
授权服务器->>资源所有者: 2. 询问用户是否授权(如微信登录弹窗)
资源所有者->>授权服务器: 3. 用户同意授权
授权服务器->>客户端: 4. 返回授权码(Authorization Code)
客户端->>授权服务器: 5. 用授权码+客户端密钥,请求访问令牌(Access Token)
授权服务器->>客户端: 6. 返回访问令牌(+可选刷新令牌 Refresh Token)
客户端->>资源服务器: 7. 用访问令牌请求资源(如用户信息)
资源服务器->>客户端: 8. 验证令牌合法,返回资源
3. 关键说明
- 授权码:短期有效(通常分钟级),仅用于兑换访问令牌,泄露风险低。
- 访问令牌(Access Token):客户端访问资源的核心凭证,有效期较短(如1小时),避免长期泄露风险。
- 刷新令牌(Refresh Token):长期有效(如30天),用于访问令牌过期后,无需用户再次授权,直接兑换新的访问令牌(仅授权码模式支持)。
- 客户端密钥(Client Secret):客户端在授权服务器注册时获取的密钥,需保存在后端(如小程序云函数、自建服务器),禁止暴露在前端(如小程序页面代码)。
二、JWT 核心概念与作用
JWT(JSON Web Token)是 令牌格式标准,用于在各方之间安全传递结构化信息(如用户身份、权限),本质是一种“自包含”的令牌(Token),无需查询数据库即可验证合法性。
1. JWT 结构(三部分用 . 连接)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInVzZXJOYW1lIjoiSmFja3kiLCJleHAiOjE3MzYxNTM2MDAsImlhdCI6MTczNjE0OTAwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- 头部(Header):指定签名算法(如 HS256、RS256)和令牌类型(JWT)。
{ "alg": "HS256", "typ": "JWT" } - 载荷(Payload):存储核心信息(如用户ID、权限、过期时间),默认不加密(仅Base64编码),禁止存储敏感信息(如密码)。
{ "userId": 1, "userName": "Jack", "exp": 1736153600, "iat": 1736149000 }- 标准字段:
exp(过期时间)、iat(签发时间)、sub(主题,如用户ID)等。 - 自定义字段:如
role(角色)、scope(权限范围)等。
- 标准字段:
- 签名(Signature):通过头部指定的算法,用密钥对“头部+载荷”进行签名,用于验证令牌是否被篡改。
- 对称加密(HS256):用同一个密钥签名和验证(适合内部系统)。
- 非对称加密(RS256):用私钥签名、公钥验证(适合跨系统,如授权服务器签发、资源服务器验证)。
2. JWT 核心优势
- 无状态:资源服务器无需存储令牌信息,仅通过签名验证即可确认令牌合法性(依赖
exp字段控制过期)。 - 跨平台/跨语言:基于JSON格式,支持所有主流语言(Java、Node.js、Python等)。
- 自包含:载荷可携带必要信息(如用户ID),减少数据库查询(无需查用户信息)。
三、OAuth 2.0 与 JWT 的关系:互补而非替代
OAuth 2.0 是 授权框架(定义“如何获取授权”的流程),JWT 是 令牌格式(定义“授权凭证”的结构),二者常结合使用,但并非强制绑定。
1. 结合使用的典型场景(最常用)
OAuth 2.0 的授权服务器颁发的 访问令牌(Access Token) 可以是 JWT 格式,流程如下:
- 客户端通过 OAuth 2.0 授权码模式,从授权服务器获取 JWT 格式的 Access Token。
- 客户端携带该 JWT 令牌请求资源服务器。
- 资源服务器收到令牌后,无需调用授权服务器验证(无状态),直接用公钥/密钥验证签名和过期时间。
- 验证通过后,从 JWT 载荷中提取用户ID、权限等信息,返回对应资源。
2. 二者的核心区别
| 维度 | OAuth 2.0 | JWT |
|---|---|---|
| 本质 | 授权协议(流程规范) | 令牌格式标准(数据结构) |
| 作用 | 解决“第三方应用如何安全获取授权” | 解决“如何安全传递令牌信息” |
| 是否必须绑定 | 否(Access Token 可是任意格式) | 否(JWT 可独立用于内部系统身份验证) |
| 状态性 | 可状态(如存储令牌到数据库) | 无状态(令牌自包含验证信息) |
| 安全性 | 依赖流程设计(如授权码模式) | 依赖签名算法(如 RS256)和密钥管理 |
3. 不结合的情况(了解即可)
- OAuth 2.0 可使用非 JWT 格式的 Access Token(如随机字符串):此时资源服务器需要调用授权服务器的接口验证令牌合法性(有状态,需查询数据库/缓存)。
- JWT 可独立使用(不依赖 OAuth 2.0):如内部系统的登录认证(用户登录后,服务器签发 JWT 令牌,客户端后续请求携带该令牌)。
四、实际开发中的应用(以小程序为例)
小程序对接第三方登录(如微信登录)时,常结合 OAuth 2.0 和 JWT,流程如下:
- OAuth 2.0 授权流程:
- 小程序通过
wx.login()获取临时登录凭证code。 - 小程序后端(云函数/自建服务器)将
code、小程序appid、appsecret发送到微信授权服务器,兑换用户唯一标识openid(相当于 OAuth 2.0 的 Access Token 流程)。
- 小程序通过
- JWT 签发与使用:
- 后端获取
openid后,生成 JWT 令牌(载荷包含openid、过期时间等),用HS256算法签名。 - 后端将 JWT 令牌返回给小程序,小程序存储在
wx.setStorageSync()中。 - 后续小程序请求后端接口时,在请求头
Authorization: Bearer <JWT令牌>中携带令牌。 - 后端接口收到请求后,验证 JWT 签名和过期时间,提取
openid识别用户身份,执行对应业务逻辑。
- 后端获取
五、关键注意事项
- JWT 不加密载荷:载荷仅 Base64 编码,任何人都可解码,禁止存储敏感信息(如密码、手机号)。
- 密钥安全:
- 对称加密(HS256)的密钥需严格保密,避免泄露。
- 推荐使用非对称加密(RS256),私钥仅授权服务器持有(用于签发令牌),公钥可公开给资源服务器(用于验证)。
- 令牌过期控制:
- JWT 的
exp字段必须设置(短期有效,如1小时),避免令牌长期泄露风险。 - 结合 OAuth 2.0 的 Refresh Token,实现令牌自动刷新(无需用户重新登录)。
- JWT 的
- 小程序端注意:
- 禁止在前端存储
appsecret、JWT 签名密钥等敏感信息。 - JWT 令牌建议放在请求头中传递,避免放在 URL 中(易被日志记录)。
- 禁止在前端存储
总结
- OAuth 2.0 是“授权的流程规则”,解决第三方应用如何安全获取用户授权的问题。
- JWT 是“令牌的包装格式”,解决令牌如何安全、无状态传递信息的问题。
- 实际开发中,二者常结合使用:OAuth 2.0 负责授权流程,JWT 作为 Access Token 的格式,实现无状态、高效的资源访问验证。
OAuth2.1并非全新协议,而是OAuth2.0的安全加固与规范整合版本,核心是剔除不安全流程、强化安全约束,简化开发者的安全配置成本,二者的核心区别集中在授权流程、安全机制、令牌使用等多个关键维度,具体如下:
-
授权流程的取舍
流程类型 OAuth2.0 OAuth2.1 授权码模式+PKCE PKCE是可选扩展,仅推荐公共客户端(如单页应用)使用,机密客户端(如后端服务器)可省略 强制所有客户端(无论公共还是机密)使用,通过code_verifier和code_challenge参数防止授权码被截获后滥用,成为授权码流程的必备条件 隐式授权模式 支持该模式,通过URL直接向前端返回访问令牌,曾用于单页应用,但令牌易通过浏览器历史、日志等泄露 彻底废除,改用“授权码模式+PKCE”替代,解决原模式的令牌泄露和无法使用刷新令牌的问题 资源所有者密码模式 允许该模式,客户端可直接收集用户用户名和密码换取令牌,虽不推荐但未强制禁止 完全移除该模式,因其违背OAuth委托授权的核心理念,不仅扩大密码泄露风险,还无法支持多因素认证等高级安全机制 除此之外,OAuth2.1仅保留授权码模式(+PKCE) 和客户端凭证模式两种核心流程,前者适配绝大多数应用场景,后者用于服务端之间的机器通信;而OAuth2.0流程选择更多,开发者需自行判断场景适配性,容易出错。
-
安全机制的强化
- 重定向URI校验:OAuth2.0对重定向URI匹配要求宽松,允许通配符或部分匹配,易被恶意篡改导致授权码泄露;OAuth2.1强制要求精确字符串匹配,彻底杜绝此类开放重定向攻击。
- 客户端认证:OAuth2.1中所有非公共客户端必须执行严格的客户端认证,如使用Client ID+Secret或证书等方式;而OAuth2.0仅对机密客户端有认证要求,公共客户端无强制约束。
- 令牌传输安全:OAuth2.0允许在URL查询参数中携带访问令牌,极易泄露;OAuth2.1明确禁止这种用法,要求令牌仅通过HTTP的Authorization请求头传输,降低泄露风险。
-
刷新令牌的安全约束
- OAuth2.0对刷新令牌的约束较弱,部分实现中刷新令牌可被重复使用,且未强制绑定客户端,存在被盗用后持续获取访问令牌的风险。
- OAuth2.1大幅强化刷新令牌安全性:一是要求刷新令牌与特定客户端实例绑定(发送者约束);二是推行“刷新令牌轮换”,每次使用后旧令牌立即失效,同时返回新的刷新令牌,避免刷新令牌被盗用后的持续风险,且明确刷新令牌仅能用于获取新访问令牌,不可直接访问资源。
-
规范整合与兼容性
- OAuth2.0基于RFC 6749和RFC 6750制定,后续的安全扩展(如PKCE、客户端元数据规范等)未整合进核心协议,开发者需自行集成以提升安全性。
- OAuth2.1主动整合了多个后续安全相关的RFC规范,比如RFC 7636(PKCE)、RFC 8252(移动和单页应用最佳实践)、RFC 8414(授权服务器元数据),将这些最佳实践固化为核心规范,无需开发者额外集成扩展功能。
综上,OAuth2.1更适合新项目开发,尤其是金融、医疗等对安全性要求高的场景;而OAuth2.0仅适合旧系统维护,且建议逐步迁移至OAuth2.1的安全规范,降低安全漏洞风险。