Published on

OAuth 2.0 核心流程笔记

Authors
  • avatar
    Name
    Terry
    Twitter

现实中的OAuth

阮一峰老师举了快递员进小区的例子。小区就是一个服务,里面是我的数据。

我可以通过用户名和密码通过门禁进入小区。但是有时候快递小哥(第三方应用)也需要进入门禁(仅限于通过小区门禁),来收发快递。

如果我把密码告诉快递员,显然不安全(权限过高),取消权限也很麻烦(需要我改密码)。怎么让快递员在进入小区的便捷性和安全性间取得平衡。

授权机制的设计

  1. 门禁系统的密码输入器下面,增加一个按钮,叫做"获取授权"。快递员需要首先按这个按钮,去申请授权。
  2. 他按下按钮以后,屋主(也就是我)的手机就会跳出对话框:有人正在要求授权。系统还会显示该快递员的姓名、工号和所属的快递公司。
  3. 门禁系统得到我的确认以后,向快递员显示一个进入小区的令牌(access token)。令牌就是类似密码的一串数字,只在短期内(比如七天)有效。
  4. 快递员向门禁系统输入令牌,进入小区。

什么是OAuth

有了前面的案例,就能更好的理解。

OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。

OAuth 的核心就是向第三方应用颁发令牌

令牌相对密码有三点差异;

(1)令牌是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。 (2)令牌可以被数据所有者撤销,会立即失效。以上例而言,屋主可以随时取消快递员的令牌。密码一般不允许被他人撤销。 (3)令牌有权限范围(scope),比如只能进小区的二号门。对于网络服务来说,只读令牌就比读写令牌更安全。密码一般是完整权限。

RFC 6749

OAuth 2.0 的标准是 RFC 6749 文件。

OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者。......资源所有者同意以后,资源服务器可以向客户端颁发令牌。客户端通过令牌,去请求数据。

OAuth 2.0 规定了四种获得令牌的流程。

  • 授权码(authorization-code)
  • 隐藏式(implicit)
  • 密码式(password):
  • 客户端凭证(client credentials)

前提

不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)

这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的。

也就是说,得确认你这个人是快递员才有资格请求令牌。其它冒充的通不过身份验证。

第一种授权方式:授权码

授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。(这种的安全性最高),像令牌。密钥都是存储在后端,前端(浏览器)没有这些信息,避免令牌泄露。

以下都是假设A网站要请求B网站的授权。

第一步 请求授权码

A会向B的授权API请求,让B知道是谁在请求,要求返回授权码,返回的重定向地址。

https://b.com/oauth/authorize?
  response_type=code&
  client_id=CLIENT_ID&
  redirect_uri=CALLBACK_URL&
  scope=read

第二步 返回授权码

用户跳转后,B 网站会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回redirect_uri参数指定的网址。跳转时,会传回一个授权码。

https://a.com/callback?code=AUTHORIZATION_CODE

第二步A拿到了B的授权码,也就是我觉得你的请求是合理的,允许你继续申请令牌。(但是为什么不就在这里直接返回令牌呢?因为这是从A前端发送的请求,我们不知道到底是是不是A的请求,因为很容易被伪造,没有能够验证身份特征的东西,就算有,在前端也是不可靠的,所以生成了一次性的验证码。那为什么不直接点击就让A的后端开始请求呢?)

第三步 请求令牌

A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。

https://b.com/oauth/token?
 client_id=CLIENT_ID&
 client_secret=CLIENT_SECRET&
 grant_type=authorization_code&
 code=AUTHORIZATION_CODE&
 redirect_uri=CALLBACK_URL

上面 URL 中,client_id参数和client_secret参数用来让 B 确认 A 的身份(client_secret参数是保密的,因此只能在后端发请求),grant_type参数的值是AUTHORIZATION_CODE,表示采用的授权方式是授权码,code参数是上一步拿到的授权码,redirect_uri参数是令牌颁发后的回调网址。

第四步 返回令牌

B 网站收到请求以后,就会颁发令牌。具体做法是向redirect_uri指定的网址,发送一段 JSON 数据。

A 网站在后端拿到 B 网站颁发的令牌。

第二种方式:隐藏式

密码登陆很重要,是把关令牌请求是否有效安全可信的关键。

HTTP 的重定向

参考

阮一峰老师系列课程: