OAuth2

OAuth是一個關於受權(authorization)的開放網絡標準,在全世界獲得普遍應用,目前的版本是2.0版。express

本文對OAuth 2.0的設計思路和運行流程,作一個簡明通俗的解釋,主要參考材料爲RFC 6749json

一 應用場景

爲了理解OAuth的適用場合,讓我舉一個假設的例子。瀏覽器

有一個"雲沖印"的網站,能夠將用戶儲存在Google的照片,沖印出來。用戶爲了使用該服務,必須讓"雲沖印"讀取本身儲存在Google上的照片。緩存

雲沖印

問題是隻有獲得用戶的受權,Google纔會贊成"雲沖印"讀取這些照片。那麼,"雲沖印"怎樣得到用戶的受權呢?安全

傳統方法是,用戶將本身的Google用戶名和密碼,告訴"雲沖印",後者就能夠讀取用戶的照片了。這樣的作法有如下幾個嚴重的缺點。服務器

(1)"雲沖印"爲了後續的服務,會保存用戶的密碼,這樣很不安全。

(2)Google不得不部署密碼登陸,而咱們知道,單純的密碼登陸並不安全。

(3)"雲沖印"擁有了獲取用戶儲存在Google全部資料的權力,用戶無法限制"雲沖印"得到受權的範圍和有效期。

(4)用戶只有修改密碼,才能收回賦予"雲沖印"的權力。可是這樣作,會使得其餘全部得到用戶受權的第三方應用程序所有失     效。

(5)只要有一個第三方應用程序被破解,就會致使用戶密碼泄漏,以及全部被密碼保護的數據泄漏。

OAuth就是爲了解決上面這些問題而誕生的。網絡

二 名詞定義

在詳細講解OAuth 2.0以前,須要瞭解幾個專用名詞。它們對讀懂後面的講解,尤爲是幾張圖,相當重要。app

(1)Third-party application:第三方應用程序,本文中又稱"客戶端"(client),即上一節例子中的"雲沖印"。An application making protected resource requests on behalf of the resource owner and with its authorization.  The term "client" does not imply any particular implementation characteristics (e.g., whether the application executes on a server, a desktop, or other devices)
(2)HTTP service:HTTP服務提供商,本文中簡稱"服務提供商",即上一節例子中的Google。
(3)Resource Owner:資源全部者,本文中又稱"用戶"(user)。
     An entity capable of granting access to a protected resource. When the resource  owner is a person, it is referred to as an end-user
(4)User Agent:用戶代理,本文中就是指瀏覽器。
(5)Authorization server:認證服務器,即服務提供商專門用來處理認證的服務器。
    The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization
(6)Resource server:資源服務器,即服務提供商存放用戶生成的資源的服務器。它與認證服務器,能夠是同一臺服務器,也能夠是不一樣的服務器。
    The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.

知道了上面這些名詞,就不難理解,OAuth的做用就是讓"客戶端"安全可控地獲取"用戶"的受權,與"服務商提供商"進行互動。框架

三 OAuth的思路

OAuth在"客戶端"與"服務提供商"之間,設置了一個受權層(authorization layer)。"客戶端"不能直接登陸"服務提供商",只能登陸受權層,以此將用戶與客戶端區分開來。"客戶端"登陸受權層所用的令牌(token),與用戶的密碼不一樣。用戶能夠在登陸的時候,指定受權層令牌的權限範圍和有效期。網站

"客戶端"登陸受權層之後,"服務提供商"根據令牌的權限範圍和有效期,向"客戶端"開放用戶儲存的資料。

運行流程

OAuth 2.0的運行流程以下圖,摘自RFC 6749

OAuth運行流程

(A)用戶打開客戶端之後,客戶端要求用戶給予受權。(The client requests authorization from the resource     owner.  The authorization request can be made directly to the resource owner(as shown), or     preferably indirectly via the authorizationserver as an intermediary.)

(B)用戶贊成給予客戶端受權。(The client receives an authorization grant, which is acredential         representing the resource owner's authorization,expressed using one of four grant types       defined in this specification or using an extension grant type.  The authorization grant       type depends on the method used by the client to request authorization and the types           supported by the authorization server)

(C)客戶端使用上一步得到的受權,向認證服務器申請令牌。
     The client requests an access token by authenticating with the
     authorization server and presenting the authorization grant
(D)認證服務器對客戶端進行認證之後,確認無誤,贊成發放令牌。
    The authorization server authenticates the client and validates
    the authorization grant, and if valid, issues an access token
(E)客戶端使用令牌,向資源服務器申請獲取資源。
		The client requests the protected resource from the resource
    server and authenticates by presenting the access token
(F)資源服務器確認令牌無誤,贊成向客戶端開放資源。
		The resource server validates the access token, and if valid,
    serves the request

四 客戶端的受權模式(Authorization Grant)

客戶端必須獲得用戶的受權(authorization grant),才能得到令牌(access token)。OAuth 2.0定義了四種受權方式

  • 受權碼模式(authorization code)

  • 簡化模式(implicit)

  • 密碼模式(resource owner password credentials)

  • 客戶端模式(client credentials)

受權碼模式(authorization code)

受權碼模式(authorization code)是功能最完整、流程最嚴密的受權模式。它的特色就是經過客戶端的後臺服務器,與"服務提供商"的認證服務器進行互動。

受權碼模式

它的步驟以下:

(A)用戶訪問客戶端,後者將前者導向認證服務器。

(B)用戶選擇是否給予客戶端受權。

(C)假設用戶給予受權,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個受權碼。

(D)客戶端收到受權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的後臺的服務器上完成的,對用戶不可見。

(E)認證服務器覈對了受權碼和重定向URI,確認無誤後,向客戶端發送訪問令牌(access token)和更新令牌(refresh token)。

下面是上面這些步驟所須要的參數。

A步驟中,客戶端申請認證的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步驟中,服務器迴應客戶端的URI,包含如下參數:

  • code:表示受權碼,必選項。該碼的有效期應該很短,一般設爲10分鐘,客戶端只能使用該碼一次,不然會被受權服務器拒絕。該碼與客戶端ID和重定向URI,是一一對應關係。
  • state:若是客戶端的請求中包含這個參數,認證服務器的迴應也必須如出一轍包含這個參數。

下面是一個例子。

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

D步驟中,客戶端向認證服務器申請令牌的HTTP請求,包含如下參數:

  • grant_type:表示使用的受權模式,必選項,此處的值固定爲"authorization_code"。
  • code:表示上一步得到的受權碼,必選項。
  • 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步驟中,認證服務器發送的HTTP回覆,包含如下參數:

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

從上面代碼能夠看到,相關參數使用JSON格式發送(Content-Type: application/json)。此外,HTTP頭信息中明確指定不得緩存。

簡化模式

簡化模式(implicit grant type)不經過第三方應用程序的服務器,直接在瀏覽器中向認證服務器申請令牌,跳過了"受權碼"這個步驟,所以得名。全部步驟在瀏覽器中完成,令牌對訪問者是可見的,且客戶端不須要認證。

簡化模式

它的步驟以下:

(A)客戶端將用戶導向認證服務器。

(B)用戶決定是否給於客戶端受權。

(C)假設用戶給予受權,認證服務器將用戶導向客戶端指定的"重定向URI",並在URI的Hash部分包含了訪問令牌。

(D)瀏覽器向資源服務器發出請求,其中不包括上一步收到的Hash值。

(E)資源服務器返回一個網頁,其中包含的代碼能夠獲取Hash值中的令牌。

(F)瀏覽器執行上一步得到的腳本,提取出令牌。

(G)瀏覽器將令牌發給客戶端。

下面是上面這些步驟所須要的參數。

A步驟中,客戶端發出的HTTP請求,包含如下參數:

  • response_type:表示受權類型,此處的值固定爲"token",必選項。
  • client_id:表示客戶端的ID,必選項。
  • redirect_uri:表示重定向的URI,可選項。
  • scope:表示權限範圍,可選項。
  • state:表示客戶端的當前狀態,能夠指定任意值,認證服務器會原封不動地返回這個值。

下面是一個例子。

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

C步驟中,認證服務器迴應客戶端的URI,包含如下參數:

  • access_token:表示訪問令牌,必選項。
  • token_type:表示令牌類型,該值大小寫不敏感,必選項。
  • expires_in:表示過時時間,單位爲秒。若是省略該參數,必須其餘方式設置過時時間。
  • scope:表示權限範圍,若是與客戶端申請的範圍一致,此項可省略。
  • state:若是客戶端的請求中包含這個參數,認證服務器的迴應也必須如出一轍包含這個參數。

下面是一個例子。

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

在上面的例子中,認證服務器用HTTP頭信息的Location欄,指定瀏覽器重定向的網址。注意,在這個網址的Hash部分包含了令牌。

根據上面的D步驟,下一步瀏覽器會訪問Location指定的網址,可是Hash部分不會發送。接下來的E步驟,服務提供商的資源服務器發送過來的代碼,會提取出Hash中的令牌。

密碼模式

密碼模式(Resource Owner Password Credentials Grant)中,用戶向客戶端提供本身的用戶名和密碼。客戶端使用這些信息,向"服務商提供商"索要受權。

在這種模式中,用戶必須把本身的密碼給客戶端,可是客戶端不得儲存密碼。這一般用在用戶對客戶端高度信任的狀況下,好比客戶端是操做系統的一部分,或者由一個著名公司出品。而認證服務器只有在其餘受權模式沒法執行的狀況下,才能考慮使用這種模式。

密碼模式

它的步驟以下:

(A)用戶向客戶端提供用戶名和密碼。

(B)客戶端將用戶名和密碼發給認證服務器,向後者請求令牌。

(C)認證服務器確認無誤後,向客戶端提供訪問令牌。

B步驟中,客戶端發出的HTTP請求,包含如下參數:

  • grant_type:表示受權類型,此處的值固定爲"password",必選項。
  • username:表示用戶名,必選項。
  • password:表示用戶的密碼,必選項。
  • scope:表示權限範圍,可選項。

下面是一個例子。

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步驟中,認證服務器向客戶端發送訪問令牌,下面是一個例子。

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

上面代碼中,各個參數的含義參見《受權碼模式》一節。

整個過程當中,客戶端不得保存用戶的密碼。

客戶端模式

客戶端模式(Client Credentials Grant)指客戶端以本身的名義,而不是以用戶的名義,向"服務提供商"進行認證。嚴格地說,客戶端模式並不屬於OAuth框架所要解決的問題。在這種模式中,用戶直接向客戶端註冊,客戶端以本身的名義要求"服務提供商"提供服務,其實不存在受權問題。

客戶端模式

它的步驟以下:

(A)客戶端向認證服務器進行身份認證,並要求一個訪問令牌。

(B)認證服務器確認無誤後,向客戶端提供訪問令牌。

A步驟中,客戶端發出的HTTP請求,包含如下參數:

  • 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步驟中,認證服務器向客戶端發送訪問令牌,下面是一個例子。

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

上面代碼中,各個參數的含義參見《受權碼模式》一節。

更新令牌

若是用戶訪問的時候,客戶端的"訪問令牌"已通過期,則須要使用"更新令牌"申請一個新的訪問令牌。

客戶端發出更新令牌的HTTP請求,包含如下參數:

  • 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
相關文章
相關標籤/搜索