OAuth2

Table of Contents generated with DocToc

  • 【RFC6749中文版】https://github.com/jeansfish/RFC6749.zh-cn
  • 【RFC6749原版】https://tools.ietf.org/html/rfc6749

OAuth2 Intro

在传统的客户端-服务器身份验证模式中,客户端请求服务器上访问受限的资源(受保护的资源)时,需要使用资源所有者的凭据在服务器上进行身份验证。 资源所有者为了给第三方应用提供受限资源的访问权限,需要与第三方共享它的凭据。这就导致一些问题和局限:

  • 第三方应用需要存储资源所有者的凭据以供将来使用。该凭据通常是明文密码
  • 服务器需要支持密码身份认证,尽管密码认证有固有的安全缺陷。
  • 第三方应用获得了对资源所有者的受保护资源的过于宽泛的访问权限,从而导致资源所有者不能限制对资源的有限子集的访问时限或权限。(不利于权限控制)
  • 资源所有者不能撤销某个第三方的访问权限而不影响其它第三方,并且必须更改他们的密码才能做到。(不利于权限撤销)
  • 与任何第三方应用的妥协导致对终端用户的密码及该密码所保护的所有数据的妥协。

OAuth通过引入授权服务器以及从资源所有者角色分离出客户端角色来解决这些问题。在OAuth中,客户端需要使用由资源所有者授权,且由授权服务器生成的凭证(access_token)来获取受保护的资源。

关键角色

  1. 资源所有者 - 对资源拥有完全权限的人
  2. 资源服务器 - 存放资源的地方
  3. 客户端 - 需要访问受限资源的地方
  4. 授权服务器 - 控制权限和资源关系的中间人

关键阶段

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

                     Figure 1: 抽象的协议流程图

AB阶段为用户授权阶段,CD阶段为获取访问凭证(access_token)阶段,EF为获取受限资源阶段。

1. 授权

1.1 授权码授权 (Authorization Code Grant)

     +----------+
     | Resource |
     |   Owner  |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier      +---------------+
     |         -+----(A)-- & Redirection URI ---->|               |
     |  User-   |                                 | Authorization |
     |  Agent  -+----(B)-- User authenticates --->|     Server    |
     |          |                                 |               |
     |         -+----(C)-- Authorization Code ---<|               |
     +-|----|---+                                 +---------------+
       |    |                                         ^      v
      (A)  (C)                                        |      |
       |    |                                         |      |
       ^    v                                         |      |
     +---------+                                      |      |
     |         |>---(D)-- Authorization Code ---------'      |
     |  Client |          & Redirection URI                  |
     |         |                                             |
     |         |<---(E)----- Access Token -------------------'
     +---------+       (w/ Optional Refresh Token)

   Note: The lines illustrating steps (A), (B), and (C) are broken into
   two parts as they pass through the user-agent.

                     Figure 3: Authorization Code Flow

故事一般由资源所有者来发起(所以你可以看到一个User-Agent,可以理解为一个浏览器),虽然从流程图上体现不出来:

  • 资源所有者想让Client获得自己某些资源的权限。(隐式,流程图上无体现)

  • Client需要访问受限资源,所以需要先获得资源所有者的同意。所以Client会引导用户进入一个由授权服务器提供的授权界面,即A阶段。

  • 浏览器将告诉用户需要填写哪些信息,并将这些信息发送给授权服务器,即B阶段。

  • 当授权服务器认证通过后,会将授权码发送给Client,即C阶段

  • Client拿到授权码后,会用授权码请求访问凭据,即D阶段

  • 授权服务器验证授权码合法后,就会将访问凭据发送给client,即E阶段。

  • 最后,Client就可以愉快的访问这些资源啦~

其中,需要注意的是,C阶段是如何将授权码返回给Client的。在A阶段时,Client会提供一个重定向地址,授权服务器认证通过后,会告诉浏览器(HTTP 302),重定向到client提供的那个地址,并带上授权码等参数。

比如:

  • A阶段,Client提供一个www.client.com/auth/code的重定向地址给授权服务器。
  • C阶段,当授权服务器完成授权后,会返回一个302响应,重定向到 www.client.com/auth/code?code=授权码&state=random_words

1.2 隐式授权 (Implicit Grant)

     +----------+
     | Resource |
     |  Owner   |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier     +---------------+
     |         -+----(A)-- & Redirection URI --->|               |
     |  User-   |                                | Authorization |
     |  Agent  -|----(B)-- User authenticates -->|     Server    |
     |          |                                |               |
     |          |<---(C)--- Redirection URI ----<|               |
     |          |          with Access Token     +---------------+
     |          |            in Fragment
     |          |                                +---------------+
     |          |----(D)--- Redirection URI ---->|   Web-Hosted  |
     |          |          without Fragment      |     Client    |
     |          |                                |    Resource   |
     |     (F)  |<---(E)------- Script ---------<|               |
     |          |                                +---------------+
     +-|--------+
       |    |
      (A)  (G) Access Token
       |    |
       ^    v
     +---------+
     |         |
     |  Client |
     |         |
     +---------+

   Note: The lines illustrating steps (A) and (B) are broken into two
   parts as they pass through the user-agent.

                       Figure 4: Implicit Grant Flow

单从流程图上可以看出来,隐式授权与授权码大致有两点不同:

  1. 无Authorization Code的颁发过程。(Client实现更加简单)
  2. Client的交互过程减少,User-Agent的交互过程增加。(减少Client压力,加快Client响应)

故事仍然由资源所有者开始:资源所有者想让Client获取到他的受限资源

  • A阶段,Client将提供一个获取访问凭证的重定向地址,并引导用户通过授权服务器提供的界面进行授权。
  • B阶段,用户进行授权行为。
  • C阶段,授权通过后,授权服务器将以302重定向响应返回,其中重定向地址中以哈希形式携带访问凭据。
  • D阶段,浏览器重定向到C阶段返回地址(没有携带访问凭据)。
  • EF阶段,目标服务器返回一个JS脚本。这个脚本将有浏览器执行,将浏览器本地保存的访问凭据获取到后,发送给Client。

1.3 密码模式 (Resource Owner Password Credentials Grant)

     +----------+
     | Resource |
     |  Owner   |
     |          |
     +----------+
          v
          |    Resource Owner
         (A) Password Credentials
          |
          v
     +---------+                                  +---------------+
     |         |>--(B)---- Resource Owner ------->|               |
     |         |         Password Credentials     | Authorization |
     | Client  |                                  |     Server    |
     |         |<--(C)---- Access Token ---------<|               |
     |         |    (w/ Optional Refresh Token)   |               |
     +---------+                                  +---------------+

            Figure 5: Resource Owner Password Credentials Flow

这个模式更简单了!

简而言之,Client直接拿着资源所有者的密码到处浪了,这个模式的前提是:资源所有者必须非常信任Client,如果你不信任Client,可千万别这么玩。

故事再次由资源所有者开始:

  • A阶段:资源所有者将密码交给Client
  • B阶段:Client通过资源所有者的密码获取访问凭证,同时可选获取刷新凭证。
  • C极端:授权服务器返回访问凭证,可选返回刷新凭证。

1.4 客户端凭据模式 (Client Credentials Grant)

     +---------+                                  +---------------+
     |         |                                  |               |
     |         |>--(A)- Client Authentication --->| Authorization |
     | Client  |                                  |     Server    |
     |         |<--(B)---- Access Token ---------<|               |
     |         |                                  |               |
     +---------+                                  +---------------+

                     Figure 6: Client Credentials Flow

简直不能更爽了,没有任何重定向,直接获取,一步到位!

这次故事不是由资源所有者开始了:

  • A阶段:Client通过客户端凭据直接请求访问凭据
  • B阶段:授权服务器返回访问凭据

这种方法有一个前提:需要资源所有者提前为Client在授权服务器上申请一个授权凭据。(有点像公有云的AKSK模式哦)