OAuth2 的几种方式
2026/06/09 oauth2
多年前,阮一峰老师写过一篇著名的《OAuth 2.0 的四种方式》,我经常把它当成字典来查。最近在折腾 Skills 开发时,随手写了一段设备码(Device Code)授权的逻辑,索性就把常见的 OAuth2 授权方式都重新整理一遍。
传统 4 种方式
先来复习一下老牌的 4 种授权方式,也就是阮一峰老师 2019 年文章中提到的经典模式。
1. 授权码模式 (Authorization Code)
这是什么? 最安全、最常见的授权方式,也就是你平时用微信、GitHub 扫码登录第三方网站的底层逻辑。
它是如何工作的?
- 前端网页引导用户跳转到 IDP(身份提供商)服务器:
oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read。 - 用户在 IDP 登录成功后,IDP 会重定向回
redirect_uri,并带上一个一次性的code。 - 后端服务器拿到
code之后,在后台用自己的client_secret偷偷去 IDP 访问:oauth/token?grant_type=authorization_code&code=AUTHORIZATION_CODE...兑换真正的 Token。
优点:非常安全,因为真正的 Token 只在后端服务器之间传递,前端根本接触不到。

2. 客户端凭证模式 (Client Credentials)
这是什么? 也叫 M2M (Machine to Machine) 方式,纯后端服务之间的“通行证”。
为什么需要它? 当没有真实用户参与,只有微服务 A 需要调用微服务 B 的接口时,就不需要弹窗让用户登录了。
它是如何工作的?
微服务的服务器直接拿着自己的账号密码找 IDP 兑换 Token:
token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
注意:这样换回来的 Token 权限通常很大(比如能读取所有数据),不像授权码模式的 Token 会绑定具体用户并限制权限。

3. 隐藏式 (Implicit) - 💀 已废弃
这是什么? 专为没有后端的纯前端应用设计。前端直接通过 client_id 获取 Token,Token 会放在 URL 的锚点(Hash)里返回,避免向服务器发送请求。
为什么废弃? Token 直接暴露在前端,极易被窃取,安全性太差。
4. 密码式 (Password) - 💀 已废弃
这是什么? 用户直接把账号密码交给第三方应用,第三方应用拿着密码去 IDP 换 Token。
token?grant_type=password&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&username=USERNAME&password=PASSWORD
为什么废弃? 相当于你把银行卡密码直接告诉了记账软件,如果应用偷偷把密码记录在日志里,风险极高。
现代追加的几种方式
随着终端设备的丰富和安全要求的提升,后来又追加了新的授权方式。
1. 设备码模式 (Device Code)
这是什么? 专为没有浏览器的设备(如 CLI 工具、智能电视、物联网设备)设计的授权方式。
它是如何工作的?
- 设备先访问 IDP 的
authorize/device/code,生成用户码和设备码。 - 设备在屏幕上显示用户码,提示用户用手机或电脑打开指定网页并输入该码确认登录。
- 同时,设备(如 CLI)在后台不断用设备码轮询 IDP:“用户登录成功了吗?”
- 用户在手机上确认后,CLI 轮询成功,拿到 Token。

2. PKCE 模式 (Proof Key for Code Exchange)
这是什么? 授权码模式的“威力加强版”,专门用来保护 CLI、手机 App、SPA 前端等无法安全存储 client_secret 的公共客户端。
为什么需要它(如何防止劫持)?
如果 CLI 是个开源工具,别人很容易逆向拿到写死在代码里的 client_id 和 client_secret。如果不验证 Secret,恶意程序就可以监听本地端口,截获 IDP 返回的 code 并自己去换取 Token。
它是如何工作的?(动态暗号机制) PKCE 的核心是不再依赖固定的 Secret,而是每次登录临时捏造一个暗号:
- 埋下伏笔:CLI 随机生成一个明文暗号(
Code Verifier),并算出它的哈希值(Code Challenge)。CLI 带着哈希值去请求授权,让 IDP 先把哈希值记在账上。 - 获取 Code:用户登录成功,IDP 下发
code(假设此时被恶意程序截获)。 - 验证暗号:恶意程序拿着
code去换 Token,但 IDP 要求提供明文暗号。恶意程序只有哈希值,无法反推明文,直接被拒。 - 成功兑换:真正的 CLI 带着
code和明文暗号去请求,IDP 验证明文的哈希值与账本一致,安全发放 Token。
总结:PKCE 就像是“先给哈希值,后验明文”,即使中间的 code 被小偷截获,小偷也因为对不上暗号而无法拿到最终的 Token。