OAuth 2.0 有哪四种授权模式?分别适合什么场景?为什么简化模式和密码模式被弃用了?
简化版
OAuth 2.0 定义了四种授权模式(grant type),针对不同的客户端类型:① 授权码模式(Authorization Code)——最安全、最主流,适合有后端的 Web 应用(授权码在前端拿、换 token 在后端做,token 不暴露给浏览器);② 简化模式(Implicit)——为纯前端 SPA 设计,token 直接返回给浏览器,因不安全已被弃用(改用授权码 + PKCE);③ 密码模式(Resource Owner Password Credentials)——用户把用户名密码直接给客户端,只适合「高度信任的自家应用」,也已被弃用(暴露密码、违背 OAuth 初衷);④ 客户端凭证模式(Client Credentials)——没有用户参与,服务和服务之间用 client_id/secret 认证,适合**机器对机器(M2M)**的调用。现在推荐:用户登录用授权码(+PKCE),服务间调用用客户端凭证。
详细版
四种授权模式对比:
| 模式 | 适用场景 | 是否有用户参与 | 安全性 | 现状 |
|---|---|---|---|---|
| 授权码(Authorization Code) | 有后端的 Web 应用 | 是 | 高(token 不经过浏览器) | 主流推荐 |
| 简化(Implicit) | 纯前端 SPA(无后端) | 是 | 低(token 暴露在浏览器) | 已弃用,改用授权码+PKCE |
| 密码(Password) | 高度信任的自家应用 | 是 | 低(密码交给客户端) | 已弃用 |
| 客户端凭证(Client Credentials) | 服务间调用(M2M) | 否 | 高 | 推荐(无用户场景) |
授权码模式流程(最重要,token 换取分两步):
1. 用户点击"用 XX 登录" → 客户端重定向到授权服务器(带 client_id、redirect_uri、scope)
2. 用户在授权服务器登录并授权
3. 授权服务器重定向回客户端的 redirect_uri,带上一个"授权码 code"(临时、一次性)
4. 客户端【后端】拿这个 code + client_secret 去授权服务器换 access_token
★ 这一步在后端做,client_secret 和 access_token 不暴露给浏览器
5. 客户端用 access_token 访问资源服务器
客户端凭证模式流程(无用户):
客户端直接用 client_id + client_secret 向授权服务器换 access_token
→ 没有用户登录、没有重定向,纯粹是"服务身份"的认证
→ 用于定时任务、微服务间调用、后台服务访问 API
⚠️ 简化模式(Implicit)和密码模式(Password)在 OAuth 2.1 里已被正式移除。简化模式的问题是 token 直接暴露在浏览器 URL/前端(易被窃取、无法安全存储);密码模式的问题是「客户端拿到了用户的明文密码」(违背了 OAuth「不把密码给第三方」的核心初衷,且客户端可能滥用/泄露密码)。现在纯前端 SPA 应该用授权码模式 + PKCE(用动态生成的校验码替代 client_secret),既安全又适配无后端的场景。
完整版教学
一、为什么有四种模式:不同客户端的差异
OAuth 2.0 要解决「让第三方应用安全地访问用户资源,而不给它用户密码」。但「第三方应用」的形态差别很大——有的有安全的后端、有的是纯前端、有的根本没有用户(服务对服务)。四种授权模式就是针对不同客户端类型设计的不同授权方式:
客户端类型不同 → 能否安全保存密钥不同 → 适合的授权方式不同:
有后端的 Web 应用:后端能安全保存 client_secret → 授权码模式(最安全)
纯前端 SPA:浏览器里没法安全保存密钥 → 曾用简化模式,现用授权码+PKCE
高度信任的自家 App:可以直接收集密码(但不推荐)→ 密码模式(已弃用)
服务对服务(无用户):没有用户,只有服务身份 → 客户端凭证模式
核心逻辑是「客户端能不能安全地保管密钥、token 会不会暴露」——这决定了该用哪种模式。理解「四种模式是为不同客户端场景设计的」,就理解了为什么不是「一种模式走天下」,也理解了为什么有的模式被弃用(它们的安全假设不成立了)。
二、授权码模式:最安全的主流方案
授权码模式(Authorization Code)是最安全、最主流的,核心设计是「授权码和 token 的换取分两步、且换 token 在后端做」:
关键的"两步换取":
第一步:用户授权后,授权服务器给客户端一个"授权码 code"(通过浏览器重定向)
→ code 是临时的、一次性的、有效期短(几分钟)
第二步:客户端【后端】拿 code + client_secret 去换 access_token
→ 这一步是后端到授权服务器的直接通信,不经过浏览器
为什么这样设计(安全性):
① access_token 不经过浏览器(在后端换取和使用)→ 不会被前端 JS/浏览器插件窃取
② client_secret 只在后端,不暴露 → 别人拿到 code 也换不了 token(缺 secret)
③ code 一次性、短时效 → 即使 code 泄露,很快失效、且只能用一次
这个「授权码换 token」的间接设计,把「敏感的 access_token」隔离在后端,浏览器只经手「临时的、单独没用的 code」——即使 code 被截获,攻击者没有 client_secret 也换不到 token。这是授权码模式安全的关键。它适合所有有后端的 Web 应用(后端能安全保管 client_secret),是「用 GitHub/微信/Google 登录」的标准实现。理解「授权码的价值在于隔离 token、两步换取」,就理解了它为什么最安全。
三、简化模式:为什么被弃用
简化模式(Implicit)是当年为纯前端 SPA(没有后端)设计的——因为 SPA 没有安全的后端来保管 client_secret、做后端换取,所以它「简化」了流程:跳过授权码,授权服务器直接把 access_token 返回给浏览器。
简化模式流程(已弃用):
用户授权 → 授权服务器直接把 access_token 放在重定向 URL 的 fragment 里返回浏览器
→ 前端 JS 从 URL 拿到 token 直接用
问题(为什么弃用):
① token 直接暴露在浏览器(URL、浏览器历史、Referer)→ 极易被窃取
② token 没法安全存储(前端存哪都不安全:localStorage 有 XSS 风险)
③ 没有 client_secret 验证,缺少一层保护
④ 无法用 refresh_token(安全考虑不发)
简化模式的根本问题是「把最敏感的 access_token 直接扔给了不安全的浏览器」,违背了「保护 token」的原则。所以它在 OAuth 2.1 中被正式移除。替代方案是授权码模式 + PKCE——PKCE(Proof Key for Code Exchange)用「客户端动态生成的一对校验码(code_verifier / code_challenge)」替代 client_secret:换 token 时要提供 code_verifier 证明「我就是发起授权的那个客户端」,这样纯前端也能安全地用授权码模式(不需要 secret 也能防止 code 被盗用)。所以现在纯前端 SPA 用「授权码 + PKCE」,不用简化模式。
四、密码模式:为什么被弃用
密码模式(Resource Owner Password Credentials)是最「简单粗暴」的——用户把用户名密码直接交给客户端,客户端拿去换 token:
密码模式流程(已弃用):
用户把用户名密码输入到"客户端"的界面
→ 客户端拿用户名密码去授权服务器换 access_token
问题(为什么弃用):
① 违背 OAuth 的核心初衷——OAuth 就是为了"不把密码给第三方"!
密码模式却让客户端直接拿到了用户密码,等于绕过了 OAuth 的意义
② 客户端能看到、可能存储、可能泄露用户的明文密码
③ 一旦客户端被攻破,用户密码直接泄露
④ 无法支持多因素认证(MFA)、无法用第三方登录
密码模式的根本矛盾是「它让客户端拿到了用户密码,而 OAuth 的整个目的就是避免这件事」。它只在「高度信任的自家第一方应用」(如自己公司的官方 App 登录自己的后端)才勉强可用,但即便如此现在也不推荐——因为它剥夺了「用户密码只交给可信的认证服务器」这个安全基线。所以密码模式在 OAuth 2.1 中也被移除。第一方应用现在也推荐用授权码模式(哪怕是自家 App)。核心记住:密码模式让密码暴露给客户端,违背 OAuth 初衷,已弃用。
五、客户端凭证模式:服务间调用
客户端凭证模式(Client Credentials)和前三种不同——它没有用户参与,是「服务对服务(机器对机器 M2M)」的认证:
客户端凭证模式流程:
客户端(一个服务)直接用自己的 client_id + client_secret
→ 向授权服务器换 access_token
→ 用这个 token 访问别的服务/API
没有用户登录、没有重定向、没有授权页面——纯粹是"服务身份"的认证
适用场景:
- 微服务之间的调用(服务 A 调服务 B 的 API)
- 定时任务/后台批处理访问 API
- 第三方系统对接(服务器到服务器)
它认证的是「客户端(服务)自己的身份」,而不是「某个用户」——所以拿到的 token 代表「这个服务」的权限,不代表任何用户。这适合所有「没有用户、只有服务身份」的场景。它和授权码模式的本质区别:授权码是「代表用户」访问资源(有用户授权),客户端凭证是「代表服务自己」访问资源(无用户)。理解「客户端凭证 = 服务身份认证、无用户」,就知道它用在微服务间调用、后台任务这类 M2M 场景。
六、选型总结与 OAuth 2.1 的收敛
把四种模式的选型和演进汇总:
| 场景 | 推荐模式 |
|---|---|
| 有后端的 Web 应用(用户登录) | 授权码模式 |
| 纯前端 SPA / 移动 App(用户登录) | 授权码模式 + PKCE |
| 服务间调用 / 后台任务(无用户) | 客户端凭证模式 |
OAuth 2.1(对 2.0 的整理)做了收敛:移除了简化模式和密码模式,强制授权码模式配合 PKCE。所以现代的 OAuth 实践只剩两条主线:① 有用户的场景 → 授权码模式(+PKCE);② 无用户的服务间调用 → 客户端凭证模式。这个收敛的逻辑就是「只保留安全的模式,淘汰会暴露 token 或密码的模式」。面试答这题的高级之处,就是能讲清「为什么简化和密码模式被弃用(安全问题)+ 现代实践收敛到授权码+PKCE 和客户端凭证」,而不只是罗列四种模式。
记忆钩子:「OAuth2 四模式:授权码(有后端 Web,token 后端换不暴露浏览器,最安全主流)、简化(纯前端,token 直给浏览器不安全→已弃用,改授权码+PKCE)、密码(用户密码给客户端违背 OAuth 初衷→已弃用)、客户端凭证(无用户,服务间 M2M);现代收敛:有用户用授权码+PKCE、无用户用客户端凭证」。
七、常见误区与追问
- 误区:四种授权模式现在都常用。 简化模式和密码模式已被弃用(OAuth 2.1 移除);现代实践只用授权码模式(+PKCE,有用户)和客户端凭证模式(无用户)。
- 误区:授权码模式的授权码就是 access_token。 不是——授权码(code)是临时一次性的中间凭证,客户端要在后端拿 code + client_secret 再换 access_token;code 单独没用(缺 secret 换不了 token)。
- 误区:简化模式和密码模式只是不推荐、还能用。 已被 OAuth 2.1 正式移除——简化模式 token 暴露浏览器不安全、密码模式让客户端拿到用户密码违背 OAuth 初衷。
- 误区:客户端凭证模式也需要用户登录。 不需要——它是服务对服务(M2M)的认证,认证的是客户端(服务)自己的身份,没有用户参与,用于微服务间调用、后台任务。
- 追问:为什么简化模式被弃用,替代方案是什么? 它把 access_token 直接返回浏览器(暴露在 URL、无法安全存储),不安全;替代方案是授权码模式 + PKCE,用动态校验码替代 client_secret,让纯前端也能安全用授权码。
- 追问:PKCE 解决什么问题? 纯前端没有安全的地方存 client_secret,PKCE 用「客户端动态生成的 code_verifier/code_challenge」替代 secret——换 token 时提供 code_verifier 证明身份,防止授权码被盗用,让无 secret 的客户端也能安全用授权码模式。
- 追问:授权码模式为什么比简化模式安全? 授权码模式的 access_token 在后端换取和使用、不经过浏览器,且 client_secret 只在后端、授权码一次性短时效;简化模式把 token 直接暴露在浏览器,易被窃取。
八、加强记忆
OAuth 2.0 的四种授权模式针对不同客户端类型:① 授权码模式(Authorization Code)——最安全最主流,适合有后端的 Web 应用,关键是「两步换取」(浏览器只拿临时一次性的授权码 code,客户端后端用 code + client_secret 换 access_token,token 不暴露给浏览器);② 简化模式(Implicit)——为纯前端设计、token 直接返回浏览器,因暴露 token 不安全已被弃用,改用授权码 + PKCE(用动态校验码替代 secret);③ 密码模式(Password)——用户密码直接给客户端,违背 OAuth「不把密码给第三方」的初衷、已弃用;④ 客户端凭证模式(Client Credentials)——无用户参与,服务用 client_id/secret 认证自己的身份,适合微服务间调用/后台任务(M2M)。OAuth 2.1 收敛:移除简化和密码模式,现代实践只剩两条——有用户用授权码(+PKCE)、无用户用客户端凭证。答这题的关键是讲清「为什么简化/密码模式被弃用(安全问题)」。一句话「授权码最安全主流(后端换 token)、简化和密码因不安全被弃用、客户端凭证用于无用户的服务间调用,现代收敛到授权码+PKCE 和客户端凭证」。