别名
这里给规范里的部分词语定义了别名,以此避免阅读时容易引发的语义饱和。
- 🐱:资源所有者(resource owner),通常是用户
- 🐟:🐱 的资源
- 🏦:资源服务器
- 🔑:凭据、密码、密钥
- 但不仅仅代表 🐱 的 🔑,也可能是客户端的 🔑,根据上下文进行李姐
- 🎟️:访问令牌
- 🎫: 刷新令牌
- 浏览器:User-Agent
- 🦶:重定向、跳转
- 浏览器🦶🐱4399.com,浏览器把用户重定向到 4399.com
因为找不到合适的 emoji,所以没有给 授权服务器 和 客户端 设置别名。
介绍
RFC 6749 是 OAuth 2.0 授权框架的定义。于 2012 年 10 月提出。
主要是提供了一些常见场景的身份验证的工具,可以当作思路参考或者建议。具体的实现可以视场景做适当调整的。

实际场景中,授权服务器可能和 🏦 属于同一个项目下,甚至两者在同一个服务里。此外,客户端也可能作为 🏦 的前端界面。
凭什么用 OAuth 2.0
要使用 OAuth 2.0,可以先看看传统的身份验证做法。
在传统的身份验证模型中,客户端直接使用 🐱 的 🔑 向服务器1表明身份,以此获取服务器上 🐱 的 🐟。
虽然很容易就能联想到一些会出现的问题,但还是把问题列一下:
- 客户端需要存储 🔑,可能直接存的明文密码。如果客户端被攻击,那么 🐱 的 🐟 就危险了。🙀。所以即便客户端开发者本身能够信任,但是做出来的程序却不一定。
- 服务器不管什么情况下都要支持密码身份验证,即使密码可能已经简单到验不验证都无所谓了。
- 客户端对 🐱 的 🐟 访问权限过于宽泛,导致 🐱 无法限制客户端能够访问的时间和能够访问的内容。比如可能只想开放给某个客户端某段时间能访问某部分资源,单纯靠 🔑 就很难做到。
- 🐱 不能撤销某一个或者某些客户端的访问权限,因为大家用的 🔑 都一样。
- ……
OAuth 通过引入授权层并将客户端的角色与 🐱 的角色分开来解决这些问题。
在 OAuth 里,客户端使用与 🐱 不同的 🔑,也就是 🎟️,用 🎟️ 访问 🐱 放在资源服务器的 🐟。
🎟️ 是授权服务器在 🐱 的批准下颁发给客户端的东西。
例如,🐱 可以授予/打印服务(客户端)/访问/🐱/放在/照片共享服务(资源服务器)/里/的/照片(🐟)/的/权限,而无需与打印服务共享 🐱 的用户名和密码。🐱 可以直接向/照片共享服务信任的授权服务器/进行身份验证,照片共享服务信任的授权服务器/颁发给/打印服务/一个特定的 🎟️ (比如只有照片读取权限的 🎟️)。
授权类型 / Authorization Grant
授权码 / Authorization Code

- 🐱 -> 客户端:看看
- 客户端 🦶 🐱 -> 授权服务器
- 🐱 -> 授权服务器:批准
- 授权服务器 🦶 🐱 -> 客户端:授权码
- 客户端 -> 授权服务器:授权码给你,给我个 🎟️
- 授权服务器 -> 客户端:🎟️
- 客户端 -> 资源服务器:🎟️ 放你,给我 🐱 的 🐟
- 资源服务器 -> 客户端:🐟
- 客户端 -> 🐱:🐟
- 🐱🐟 -> 😺
客户端引导 🐱 到授权服务器那边,授权服务器会在取得 🐱 授权之后引导 🐱 带着 🐱 的授权码返回到客户端。
因为是 🐱 到授权服务器上授权,所以客户端无法得知 🐱 的 🔑。
隐式 / Implicit
Tip
隐式授权流程和授权码流程非常相似,但是因为没有中间 🔑 发出(例如授权码),所以叫作隐式授权。
隐式授权是 授权码 / Authorization Code 方式的简化版本,针对 JavaScript 等脚本语言在浏览器里运行的客户端进行了优化。使用这种方式,客户端可以直接收到 🎟️ 而非授权码。
使用这种方式,通常授权服务器不会验证客户端的身份,而是直接根据将最终 🎟️ 传给客户端时使用的重定向 URI 来验证客户端身份。
比如当前网站 nafnix.com/login 要跳到授权服务器的网站 http://auth.example.com/authorize 上让用户授权登录,那就可能会是这样子跳转过去:
http://auth.example.com/authorize?redirect_uri=nafnix.com/login&其他参数...
当 🐱 跳转到 http://auth.example.com/authorize 授权时,http://auth.example.com 授权服务器会验证 nafnix.com/login 有没有资格获取 🐱 的授权。具体可能是有个客户端注册界面,需要通过 auth.example.com 获取 🐱 授权的客户端需要先在那边注册自己。
客户端得到 🎟️ 之后也可以分发给其他客户端,或者 🐱 自己也可以拿去用,取决于客户端的具体业务。
隐式授权可以提高一些客户端的响应能力和效率,因为减少了获取访问令牌所需的往返次数。但是也有可能会把 🎟️ 暴露给其他一些对 🐱 的浏览器有访问权限的程序,例如浏览器扩展程序。
- 🐱 -> 客户端:看看
- 客户端 🦶 🐱 -> 授权服务器
- 🐱 -> 授权服务器:批准
- 授权服务器 🦶 🐱 -> 客户端:🎟️
- 客户端 -> 资源服务器:🎟️ 放你,给我 🐱 的 🐟
- 资源服务器 -> 客户端:🐟
- 客户端 -> 🐱:🐟
- 🐱🐟 -> 😺
客户端 🔑
如果授权范围局限在客户端控制下的受保护资源/或者/事先与授权服务器商定好的受保护资源,那么可以使用客户端 🔑。
通常用在 🐱 自己的客户端或者事先在授权服务器上申请的受限制的资源访问(注册时就已经限制了访问范围的客户端)。
- 🐱 -> 客户端:看看
- 客户端 -> 授权服务器:🔑 放你,给我 🎟️
- 授权服务器 -> 客户端:🎟️,可选的刷新令牌
- 客户端 -> 资源服务器:🎟️ 放这里,给我 🐱 的 🐟
- 资源服务器 -> 客户端:🐟
- 客户端 -> 🐱:🐟
- 🐱🐟 -> 😺
访问令牌 🎟️
用于获取 🐱 的 🐟 的 🔑,表示向客户端发出的授权许可证明。对于客户端来说,看起来像个随机字符串,其中应含有访问范围和持续时间。
现在使用 JWT 作为访问令牌的比较多。这几年又有个 paseto 说是比 JWT 更好的东西。但是看了看感觉网站做得有些丑。
刷新令牌 🎫
刷新令牌也用来获取 🎟️,由授权服务器颁发,在目前使用的 🎟️ 失效时获取新的 🎟️,新的 🎟️ 的权限范围应该和旧的相同或是更少,生命周期也是相同或是更少。
使用刷新令牌获取新的 🎟️ 时,授权服务器也可以再返回新的刷新令牌。
客户端登记
首先,客户端要到授权服务器那边注册。
OAuth 不要求客户端直接与授权服务器交互。如果授权服务器允许,可以依靠其他方式建立信任关系来取得客户端属性。例如重定向 URI、客户端类型。
在授权服务器上注册客户端的时候,客户端开发者应该提供如下信息:
- 客户端类型
- 重定向到客户端的 URI
- 授权服务器所需的任何其他信息(例如应用程序名称、网站、描述、Logo 图片、接受法律条款)
客户端类型
授权服务器不应该对客户端类型做出假设。
客户端可以被实现为一组分布式组件,每个组件具有不同的客户端类型和安全上下文(例如,具有基于机密服务器的组件和基于公共浏览器的组件的分布式客户端)。如果授权服务器不为此类客户端提供支持或不提供有关其注册的指导,则客户端应该将每个组件注册为单独的客户端。
机密客户端
能够 保证其拥有的 🔑 安全。
例如在安全的服务器上运行的 Web 程序,访问该 Web 程序的 🐱 无法获取该 Web 程序拥有的 🔑。
公共客户端
无法 保证其拥有的 🔑 安全。
例如基于 浏览器 的程序和本机应用程序,例如浏览器(浏览器)、git(本机应用程序)。
Footnotes
-
这里故意没有区分授权服务器和🏦 ↩