OAuth 2.0 综述

OAuth 2.0 rfc6749 规范
OAuth 2.0 rfc6749 规范-带目录,阅读 RFC 文档的 工具
OAuth 官网html

OAuth 是受权(authorization)框架,描述了系统中不一样角色(服务提供商、用户、第三方应用)之间怎么实现交互。目前普遍使用的是 2.0 版本。web

常见的应用场景(估计全部人都见过):受权登陆注册。好比微信有不少用户,且微信提供了 OAuth2 接口。在个人网站上,为了简化用户注册流程,对接了微信提供的这个接口,而且在注册页面提供一个“经过微信登陆”的连接或二维码,用户点击后会跳转到微信的受权登陆页面(或者微信扫码进入受权页面),微信在用户受权后会将这个用户的基本信息发到个人网站,完成注册。注册后,每次均可以经过微信受权登陆了。json

若是须要作微信这样的平台型应用,为不少合做伙伴提供受权认证服务,能够考虑搭建本身的 OAuth 2.0 系统。可是要明白,这是挺复杂的一个系统。对于大部分应用开发人员,须要掌握的是如何调用其余平台的接口。浏览器

OAuth2 核心

角色

OAuth2 提供了 4 种角色:安全

  • Resource Owner:资源拥有者,例如一个微信用户
  • Resource Server:资源服务器,例如微信用户的基本信息所在的服务器,能够跟受权服务器在同一台服务器上
  • Client:客户端(第三方应用,即资源使用者,也叫 Third-party application),例如个人网站须要使用微信用户的帐号登陆,我就是资源使用者
  • Authorization Server:受权服务器,管理 Resource Owner,Client 和 Resource Server 三者的关系

另外的经常使用名词有:bash

  • HTTP service:HTTP 服务的提供商,例如微信、GitHub。
  • User-Agent:用户代理,通常指浏览器。

Token 类型

token 都是字符串,受权服务器须要保存全部的 token 及对应的受权信息,以便校验请求。服务器

access token 访问令牌

用于访问受保护资源的凭证。这个凭证表示特定访问范围和可用时间,由资源全部者受权,并由资源服务器和受权服务器执行,并发给客户端。微信

对资源的访问,须要 access token。并发

refresh token 刷新令牌

用于再次获取 access token 的凭证。这是可选项,能够自行决定是否让受权服务器发布 refresh token。若是发布 refresh token,会跟 access token 一同发出。refresh token 能够在 access token 失效后获取新的 access token,也能够获取更多一个 access token。app

refresh token 只会跟受权服务器交互,不会发送到资源服务器。

Client 类型

Client 有两种类型:

  • 公开的:密码会发给 Client,因此 Client 可能会泄露密码。这个过程当中密码传输到终端设备,例如浏览器,APP。
  • 私有的:密码不会发给 Client,因此 Client 不会泄露密码。

客户端配置

  • Web 应用:各个网站的微信受权登陆就是典型的 Web 应用
  • User Agent(用户代理)应用:对于浏览器上运行的 JavaScript 应用,浏览器就是用户代理。用户代理应用能够保存在 web 服务器上,但应用程序只运行一次下载的用户代理。
  • 原生应用:没法保证 secret 的安全。

Access Token 的类型

详细差别能够参考 这里

bearer 类型

参考 RFC6750

经过在请求中简单地包含访问令牌字符串来使用:

GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer mF_9.B5f-4.1JqM

mac 类型

参考 OAuth-HTTP-MAC

经过发出消息认证代码(MAC)密钥以及用于签署 HTTP 请求的某些组件的访问令牌来使用:

GET /resource/1 HTTP/1.1
Host: example.com
Authorization: MAC id="h480djs93hd8",
                   nonce="274312:dj83hs9s",
                   mac="kDZvddkndxvhGRXZhvuDjEWhGeE="

OAuth 协议的抽象工做流程

+--------+                               +---------------+
     |        |--(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: 抽象的协议流程

详细步骤以下:

  1. (A) 客户端向资源拥有者请求受权。受权请求能够直接发送到资源全部者(如上图所示),或最好间接经由受权服务器做为中介。
  2. (B) 用户向客户端受权。这是表明了资源全部者受权的一个凭证。权限授予类型取决于客户端请求时受权使用的方法和受权服务器支持的类型。
  3. (C) 客户端经过向受权服务器进行认证并提交上一步得到的受权来请求令牌 access token。
  4. (D) 受权服务器验证客户端,并验证客户端提交的受权,若是有效,则发出令牌 access token。
  5. (E) 客户端向资源服务器请求受限资源,并经过提交 access token 来验证权限。
  6. (F) 资源服务器验证 access token,若是有效,则提供资源。

在步骤 B 中,客户端能够得到用户的受权。有四种受权模式。

受权模式

第三方应用必须获得用户受权(authorization grant)后才能得到访问令牌(access token)。OAuth2 支持四种受权模式:

  • Authorization Code:受权码模式,私有和公共的 Client 均可以经过 authorization code 来获取 access token。用户经过重定向 URL 返回到 Client 后,Client 的应用程序将从 URL 获取受权码并使用它来请求 access token。
  • Implicit:隐式受权模式(简化模式),是供公开的 Client 使用的简化流程,其中 access token 在没有受权码交换的状况下当即返回。一般不推荐使用隐式流(而且一些服务器彻底禁止该流)。 建议公开的 Client 使用受权代码流而不使用客户端密钥。
  • Password:密码模式,经过用户凭证(密码)来获取 access token。此时 Client 须要用户输入密码,因此不该该被第三方客户使用。 在此流程中,用户的用户名和密码直接交换为 access token。
  • Client Credentials:客户端模式,由 Client 用来在用户上下文以外获取 access token。一般被客户用来访问他们本身的资源,而不是用户的资源。Client 也是资源全部者,能够访问本身的资源。

另外,对于已经受权的 Client,还有两种方式能够再次获取 access token:

  • Device Code:设备代码受权模式,用于无浏览器或不方便输入的设备。经过以前得到的 device code 来获取 access token。
  • Refresh Token:在 Client 端的 access token 过时时,经过 refresh token 获取 access token。Client 能够经过这种方式保证 access token 的有效性(access token 的有效期一般很短),而无需与用户进一步交互。

受权码模式

最经常使用,微信、GitHub 等的受权登陆注册就是这种方式。使用这种模式时,受权服务器会直接将受权发送到客户端的后台服务器,不须要通过用户代理,安全可靠。

+----------+
     | 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)

   注意:说明步骤(A),(B)和(C)的行在经过用户代理时分为两部分。

                     Figure 3: 受权码模式的流程

受权码模式用于获取访问令牌和刷新令牌,并针对机密客户端进行了优化。受权码模式基于重定向,受权开始时从客户端跳转到受权服务器的页面,受权完成后受权服务器后台通知客户端,同时跳转回客户端的页面。客户端必须可以与资源全部者的用户代理(一般是 Web 浏览器)进行交互,而且可以从受权服务器接收传入请求。

详细步骤

  1. (A)资源全部者访问客户端,客户端将其导向受权服务器。
  2. (B)受权服务器验证资源全部者(经过用户代理)并肯定资源全部者是否授予或拒绝客户端的访问请求。
  3. (C)假设资源全部者授予访问权限,受权服务器使用先前提供的重定向 URI 将用户代理重定向回客户端。重定向 URI 包括受权码和客户端先前提供的任何本地状态。
  4. (D)客户端经过受权码向受权服务器请求令牌。这一步对用户无感知。
  5. (E)受权服务器验证客户端和受权码,并确保收到的重定向 URI 与步骤 C 中用于重定向客户端的 URI 匹配。若是有效,受权服务器将返回访问令牌和可选的刷新令牌。

受权请求(对应步骤 A)

客户端经过 GET 方式使用如下参数来构造请求 URI:

  • response_type:必选。受权类型。只能是“code”。
  • client_id:必选。客户端的 ID。
  • redirect_uri:可选。重定向 URI。
  • scope:可选。申请权限的范围。
  • state:可选。客户端用于维护请求和回调之间状态的不透明值。受权服务器会原封不动的返回。该参数应该用于防止跨站点请求伪造。

受权请求示例:

GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com

受权响应(对应步骤 C)

受权服务器的响应也是“application/x-www-form-urlencoded”格式,包含如下参数:

  • code:必选。受权码。有效时间很短,建议设为10分钟(微信的是 2 小时)。一次有效,再次使用时会被受权服务器拒绝。受权码跟客户端 ID 和重定向 URI 绑定。
  • state:若是受权请求中包含这个参数,则必定会返回。

受权响应示例:

HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz

令牌申请请求(对应步骤 D)

客户端经过 POST 方式使用“application/x-www-form-urlencoded”格式将如下参数来构造请求 URI:

  • grant_type:必选,受权模式,只能是“authorization_code”。
  • code:必选,步骤 C 中获取的受权码。
  • redirect_uri:必选,重定向 URI,必须与步骤 A 中的保持一致。
  • client_id:必选,客户端 ID。

示例:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

令牌申请响应(对应步骤 E)

受权成功后,响应包含如下参数:

  • access_token:必选,访问令牌。
  • token_type:必选,令牌类型,该值大小写不敏感,能够是 bearer 类型或 mac 类型。
  • expires_in:过时时间,单位秒。若是用其余方式设置了过时时间,则能够省略该参数。
  • refresh_token:可选,更新令牌,用来获取下一次的访问令牌。
  • scope:可选,权限范围,默认若是与客户端申请的范围一致

示例:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{ "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }

隐式受权模式(简化模式)

+----------+
     | 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 |
     |         |
     +---------+

   注意:说明步骤(A)和(B)的行在经过用户代理时分为两部分。

                       Figure 4: 隐式受权模式的流程

隐式受权特色

  • 直接在浏览器中向认证服务器申请令牌,全部步骤在浏览器中完成,不须要跟客户端服务器交互,跳过了”受权码”这个步骤。
  • 只支持获取访问令牌,不支持刷新令牌,而且针对操做特定重定向 URI 的公共客户端进行了优化。
  • 令牌对访问者可见,且不须要客户端认证。
  • 与受权码模式(客户端对受权和获取访问令牌发出两个独立请求)不一样,客户端会在受权请求的响应中接收访问令牌(同一个请求中)。
  • 隐式受权不验证客户端身份,而且依赖于资源全部者的存在和重定向 URI 的注册。因为访问令牌被编码到重定向 URI 中,所以可能会暴露给资源全部者和同一设备上的其余应用程序。

详细步骤

  1. (A) 客户端将用户导向受权服务器,须要包含如下参数:客户端 ID、scope、state、重定向 URI。
  2. (B) 受权服务器认证资源全部者(经过用户代理),并判断是否向客户端受权。
  3. (C) 假设受权成功,受权服务器会使用上面提供的重定向 URI 跳转回客户端,并在 URI 的片断中附加 access token。
  4. (D) 用户代理(通常是浏览器)向资源服务器发请求,不包含上面附加 access token 的 URI 片断。
  5. (E) 资源服务器返回网页(一般是内嵌了脚本的 HTML 文档),用于获取完整的包含 access token 的重定向 URI 的。
  6. (F) 用户代理执行上一步获取的脚本,提取 access token。
  7. (G) 用户代理将 access token 发送到客户端。

受权请求

客户端经过添加下面的参数来构造请求 URI

  • response_type:必选。受权类型。只能是“token”。
  • client_id:必选。客户端的 ID。
  • redirect_uri:可选。重定向 URI。
  • scope:可选。申请权限的范围。
  • state:可选。客户端用于维护请求和回调之间状态的不透明值。受权服务器会原封不动的返回。该参数应该用于防止跨站点请求伪造。

客户端使用 HTTP 重定向响应或经过用户代理可用的其余方式将资源全部者定向到构造的 URI。示例:

GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
    &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com

受权服务器必须验证 redirect_uri 参数是否和客户端预留的参数一致。

Access Token 响应

用户受权后,受权服务器会颁发一个 access token 并发送到客户端,可用参数以下:

  • access_token:必选,访问令牌。
  • token_type:必选,令牌类型,该值大小写不敏感,能够是 bearer 类型或 mac 类型。
  • expires_in:过时时间,单位秒。若是用其余方式设置了过时时间,则能够省略该参数。
  • scope:可选,权限范围,默认若是与客户端申请的范围一致。
  • state:若是受权请求中包含这个参数,则必定会返回。

注意:这里没有 refresh token。

示例:

HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
           &state=xyz&token_type=example&expires_in=3600

密码模式

+----------+
     | 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: 密码模式流程

资源全部者将用户名和密码发送给客户端,而后客户端用这些凭证获取受权。

详细步骤

  1. (A)资源全部者向客户端提供用户名和密码。
  2. (B)客户端将用户名和密码发给认证服务器,请求访问令牌。
  3. (C)认证服务器向客户端提供访问令牌。

令牌申请请求(对应步骤 B)

客户端经过 GET 方式使用如下参数来构造请求 URI:

  • grant_type:必选。受权类型。只能是“password”。
  • username:必选。资源全部者的用户名。
  • password:必选。资源全部者的密码。
  • scope:可选。申请权限的范围。
  • state:可选。客户端用于维护请求和回调之间状态的不透明值。受权服务器会原封不动的返回。该参数应该用于防止跨站点请求伪造。

受权请求示例:

POST/token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=johndoe&password=A3ddj3w

令牌申请响应(对应步骤 C)

受权成功后,响应包含如下参数:

  • access_token:必选,访问令牌。
  • token_type:必选,令牌类型,该值大小写不敏感,能够是 bearer 类型或 mac 类型。
  • expires_in:过时时间,单位秒。若是用其余方式设置了过时时间,则能够省略该参数。
  • refresh_token:可选,更新令牌,用来获取下一次的访问令牌。
  • scope:可选,权限范围,默认若是与客户端申请的范围一致

示例:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{ "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }

客户端模式

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

                     Figure 6: Client Credentials Flow

客户端以本身的名义,而不是以用户的名义,向”服务提供商”进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以本身的名义要求”服务提供商”提供服务,其实不存在受权问题。

详细步骤

  1. (A)客户端向认证服务器进行身份认证,并要求一个访问令牌。
  2. (B)认证服务器确认无误后,向客户端提供访问令牌。

令牌申请请求(对应步骤 A)

客户端经过 GET 方式使用如下参数来构造请求 URI:

  • grant_type:必选。受权类型。只能是“client_credentials”。
  • scope:可选。申请权限的范围。

受权请求示例:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

令牌申请响应(对应步骤 B)

受权成功后,响应包含如下参数:

  • access_token:必选,访问令牌。
  • token_type:必选,令牌类型,该值大小写不敏感,能够是 bearer 类型或 mac 类型。
  • expires_in:过时时间,单位秒。若是用其余方式设置了过时时间,则能够省略该参数。
  • refresh_token:可选,更新令牌,用来获取下一次的访问令牌。
  • scope:可选,权限范围,默认若是与客户端申请的范围一致

示例:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{ "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "example_parameter":"example_value" }

刷新过时的 Access Token

+--------+                                           +---------------+
  |        |--(A)------- Authorization Grant --------->|               |
  |        |                                           |               |
  |        |<-(B)----------- Access Token -------------|               |
  |        |               & Refresh Token             |               |
  |        |                                           |               |
  |        |                            +----------+   |               |
  |        |--(C)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(D)- Protected Resource --| Resource |   | Authorization |
  | Client |                            |  Server  |   |     Server    |
  |        |--(E)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(F)- Invalid Token Error -|          |   |               |
  |        |                            +----------+   |               |
  |        |                                           |               |
  |        |--(G)----------- Refresh Token ----------->|               |
  |        |                                           |               |
  |        |<-(H)----------- Access Token -------------|               |
  +--------+           & Optional Refresh Token        +---------------+

               Figure 2: 刷新过时的 Access Token

详细步骤

  1. (A) 客户端经过向受权服务器进行身份验证并提交受权许可来请求 access token。
  2. (B) 受权服务器对客户端进行身份验证并验证受权许可,若是有效,则发出 access token 和 refresh token。
  3. (C) 客户端向资源服务器递交 access token,以访问受保护的资源。
  4. (D) 资源服务器验证 access token,若是有效,则提供资源。
  5. (E) 重复进行上面两个步骤,直到 access token 过时。若是客户端知道 access token 过时,跳到第 7 步,不然继续发出访问资源的请求。
  6. (F) 由于 access token 已经失效了,资源服务器报错“invalid token error”。
  7. (G) 客户端经过向受权服务器进行身份验证并提交 refresh token 来请求 access token。客户端的受权请求基于客户端类型和受权服务器的策略。
  8. (H) 受权服务器验证客户端并验证 refresh token,若是有效则发出新的 access token(也能够发出一个新的 refresh token)。

令牌申请请求(对应步骤 G)

客户端经过 GET 方式使用如下参数来构造请求 URI:

  • grant_type:必选。受权类型。只能是“refresh_token”。
  • refresh_token:必选项。以前收到的更新令牌。
  • scope:可选。申请权限的范围。

受权请求示例:

POST/token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
相关文章
相关标签/搜索