博客 / 詳情

返回

OAuth 2.0認證框架介紹

引言

關於應用系統用户身份管理需求,包括身份認證、權限授權、單點登錄、聯合身份認證等業務場景,業界有一堆的標準和規範,比如單點登錄的CAS、Kerberos,第三方身份認證OpenID,第三方用户授權OAuth,聯合身份認證和授權數據標準SAML等。每種技術有各自的應用場景,也存在交叉場景,想要把他們搞清楚,需要了解各種技術的工作原理和應用場景。今天就從其中一個技術開始,對OAuth2.0用户授權框架做一個簡單介紹,想對框架全面瞭解的可以參考框架的標準 RFC6749。

598px-Oauth_logo.svg.png

OAuth概述

引用維基百科介紹,OAuth主要的應用場景為:

開放授權(OAuth)是一個開放標準,允許用户讓第三方應用訪問該用户在某一網站上存儲的私密的資源(如照片,視頻,聯繫人列表),而無需將用户名和密碼提供給第三方應用。

舉一個通俗的例子,用户把照片、視頻、聯繫人數據存儲在內容託管雲服務R(Resource)中的Picture、Video、Contact三個模塊中;用户使用在線照片打印服務P(Printer),用户需要讓P服務讀取R服務中的照片進行打印,但不想讓P服務讀取R服務中的其他數據。

傳統方式下,用户只能向P服務提供R服務的用户名密碼,P服務通過用户名密碼登錄R服務,讀取照片,並且不能限制P服務讀取的範圍。

使用OAuth框架,通過以下授權流程,在不暴露用户密碼的情況下,向P服務授予有限的操作S服務的權限,整體流程如下:

  1. 用户登錄P服務,點擊獲取R服務權限的鏈接。
  2. 瀏覽器跳轉到R服務,用户登錄R服務後,跳出向P服務授予權限的界面。
  3. 用户選擇授予Picture模塊只讀有效期1小時三個權限的授權選項,並提交。
  4. 頁面跳轉回P服務,並攜帶R服務生產的授權碼(Picture模塊只讀權限)。
  5. P服務獲得授權碼,通過授權碼(附加clint_id和client_secret)向R服務發起讀取Picture模塊請求。
  6. R服務驗證用户信息和授權碼後,向P服務提供Picture的讀取權限。

OAuth發展至今,共有三個版本,分別為:初始化版本OAuth1.0;漏洞修復版本OAuth 1.0a;不向後兼容的OAuth2.0版本。

2.0版本主要是修復了前面版本的安全漏洞,對授權的流程進行了優化,提供了更豐富的使用場景,由於優化精簡了授權的步驟,所以不能向後兼容。本文重點介紹OAuth2.0的業務流程,為便於描述,下文如果沒有特殊説明OAuth指的就是OAuth2.0。

服務角色

根據RFC描述,定義了4中服務角色,分別描述如下:

  1. 資源所有者 Resource Owner
能夠授予對受保護資源的訪問權限的實體,當資源所有者是人員時,資源所有者就是最終用户。
  1. 資源服務器 Resource Server
託管受保護資源的服務器,能夠使用訪問令牌(Access Token)接受和響應受保護的資源請求。
  1. 客户端 Client
代表資源所有者,經其授權後向受保護資源發起請求的應用程序。
  1. 授權服務器 Authorization Server
授權服務器對資源所有者進行認證並獲取授權後,向客户端頒發訪問令牌(Access Token)

協議運行流程

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

上圖描述了協議定義的四中角色的交互關係和流程的步驟。
A) 客户端向資源所有者申請授予資源訪問權限。如示例中的P服務授予授權界面。
B) 資源所有者向客户端授予資源訪問授權。如示例中的用户授予予Picture模塊只讀有效期1小時三個權限的授權選項,並把授予的權限憑證返回給客户端。根據使用場景,Oauth規範定義了四中權限授予類型,具體在下文描述。
C) 客户端向授權服務器提交授權憑證,申請獲取授權令牌。
D) 授權服務器校驗憑證,並向客户端返回授權令牌。
E) 客户端向資源服務器提交授權令牌,申請訪問資源。
F) 資源服務器校驗令牌合法性,並向客户端提供資源服務。

客户端註冊

客户端在申請授權服務前,需要先到認證服務器上註冊。以GitHub作為授權服務器為例,用户先到Register a new OAuth application註冊一個第三方應用。註冊後,系統為應用生成Client ID和Client Secret兩個參數,用户後續的授權。

註冊頁面
image.png

註冊結果
image.png

權限授予類型

授權授予是表示資源所有者授權客户端的權限憑據,客户端使用此憑證獲取訪問令牌。規範定義了四種授權類型:授權代碼模式(Authorization code)、隱含模式(Implicit)、資源所有者密碼憑據模式(Resource Owner Password)和客户端憑據模式(Client Credentials),概述如下。

授權代碼模式(Authorization code)

授權代碼模式是功能最完善,流程最嚴密,安全性最好的授權模式。這種模式和其他模式的最大區別,是授權過程中,由客户端的後台服務器端參與,即要求客户端是有後台服務器端處理能力的服務,如Web服務。

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

需要特別説明下,Client以Web服務為例,這裏的Client是指Client的後台服務器端,User-Agent是指瀏覽器,授權的流程如下。
A) 用户打開瀏覽器,訪問Client的Web頁面,點擊獲取授權鏈接;瀏覽器把用户重定向到授權服務器。
B) 用户通過認證憑證(用户名密碼)登錄授權服務器。
C) 用户在授權服務器授權頁面選擇要授權給Client訪問的權限並提交;提交後,授權服務器生成授權代碼,把瀏覽器重定向到附帶授權代碼的Client指定的頁面;Client頁面將授權代碼提交到自己的後台服務器端。
D) Client後台服務把授權代碼+client_id+client_secret(後兩者在客户端向授權服務器註冊時生成)提交給授權服務器進行驗證。
E) 授權服務器驗證通過後,向Client返回Access Token和Refresh Token(可選)。
之後,Client就可以拿個Access Token,向資源服務器請求獲取資源的服務。

下面在介紹下各步驟的請求和返回內容。
獲取授權碼請求
請求示例:

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

參數説明:

  1. response_type,必填。固定為code
  2. client_id,必填。Client向授權服務器註冊時生成的ID。
  3. redirect_uri,可選。授權成功後返回授權代碼的重定向地址,此地址也可以在授權服務器上註冊。
  4. scope,可選。指定訪問請求的範圍,含義由授權服務器設計。
  5. state,推薦。客户端用來在請求和回調之間保持狀態的不透明值。授權服務器在將user-agent重定向回客户端時包含此值。參數用於防止跨站請求偽造。

獲取授權代碼響應
如果授權成功,則授權服務器通過URL重定向向Client返回授權代碼。
響應示例:

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

參數説明:

  1. code,必填。授權成功後授權服務器生成的授權代碼,基於安全性考慮,授權代碼由如下要求

    • 授權代碼需要設置較短的過期時間,以減輕授權代碼泄露的風險,一般推薦10分鐘。
    • 授權代碼只能使用一次,如果多次使用,則此授權代碼相關的所有Token都會被撤銷。
  2. state。和Request中的參數對應。

獲取Access Token請求
請求示例:

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

參數説明:

  1. grant_type,必填。固定為authorization_code
  2. code,必填。授權代碼。
  3. redirect_uri。和獲取授權碼請求地址一致。
  4. client_id,必填。客户端的client_id。
關於client_secret
根據網上其他資料描述,此請求request-body中還需要攜帶client_secret參數,以保證授權的安全性。但是根據RFC規範的描述,並不推薦使用此方式,而是推薦使用瀏覽器的HTTP Basic authentication認證方案,如上例所示:把認證信息(client_id:client_secret)Base64編碼後放在HTTP頭的Authorization字段中。

獲取Access Token響應
響應示例:

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"
}

參數説明:

  1. access_token,必填。訪問令牌。
  2. token_type,必填。令牌類型,可以是bearer類型或mac類型。
  3. expires_in。過期時間,單位為秒。如果省略該參數,必須其他方式設置過期時間。
  4. refresh_token,可選。更新令牌,用與獲取下一次的訪問令牌。
  5. scope,可選。權限範圍,客户端申請填寫的一致。

隱含模式(Implicit)

隱含模式(implicit grant type)授權過程不需要Client後台服務器端參與,直接在瀏覽器中向授權服務器申請令牌,跳過了"授權碼"這個步驟。所有步驟在瀏覽器中完成,令牌對訪問者是可見的,且客户端不需要認證。

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

資源所有者密碼憑據模式(Resource Owner Password)

資源所有者密碼憑據模式中,用户向客户端提供自己的用户名和密碼。客户端使用這些信息,向授權服務器索要授權。

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

客户端憑據模式(Client Credentials)

當客户端請求訪問其控制下的受保護資源時,客户端只能使用其客户端憑據(或其他支持的身份驗證方法)來請求訪問令牌。或者其他資源擁有者之前與授權服務器安排好的資源擁有者(其方法不在本文的範圍之內)。客户端憑據授予類型必須僅供機密客户端使用。

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

刷新令牌Refresh Token

在授權代碼模式和資源所有者密碼憑據模式中,獲取Access Token的過程中會返回可選的Refresh Token,Refresh Token用於獲取Access Token。由於Access Token需包含在每個和資源服務器的請求中,使用頻率高,所以應該設置較短的有效期,以減少泄露帶來的風險,當Access Token過期是,可以通過Refresh Token中授權服務器中換取新的Access Token。
刷新過期的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        +---------------+
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.