1. 程式人生 > >OAuth2.0協議及五種授權模式

OAuth2.0協議及五種授權模式

OAuth:一個關於授權(authorization)的開放網路標準,目前版本是2.0版。

為何要使用OAuth協議呢?OAuth協議的應用場景。

第三方服務方提供服務,某些服務需要使用者的同意才能夠做到,好比客廳要裝修,需要得到主人的同意,拿到鑰匙,才能裝修,提供服務。

傳統做法:

把所有鑰匙(賬號密碼)給工人。但這樣,工人可能用這個鑰匙開臥室的門。甚至打一個新的鑰匙。

缺點:(不安全)

1)服務提供方只是提供一個服務,為了保證服務能提供,就會儲存賬號密碼以供下次提供,這顯然不安全。

2)服務提供方有了賬號密碼,就擁有了使用者所有的權利,使用者沒辦法限制服務提供方獲得許可權的範圍和有效期。

3)使用者只有修改密碼,才能收回賦給服務方的權力。這樣做,會使得其他所有獲得使用者授權的第三方全部失效。

4)只要有一個第三方應用程式被破解,就會導致使用者密碼洩漏,以及所有被密碼保護的資料洩漏

OAuth可以解決這些問題。

一些概念名詞:

1)Third-party application:第三方應用程式(client)。

2)HTTP service:HTTP服務提供商。

3)Resource Owner:資源所有者-"使用者"(user)。

4)User Agent:使用者代理-瀏覽器。

5)Authorization server:認證伺服器,即服務提供商專門用來處理認證的伺服器。

6)Resource server:資源伺服器,即服務提供商存放使用者生成的資源的伺服器。它與認證伺服器,可以是同一臺伺服器,也可以是不同的伺服器。

OAuth的作用就是讓"客戶端"安全可控地獲取"使用者"的授權,與"服務商提供商"進行互動。

Oauth設計理念

OAuth在"客戶端"與"服務提供商"之間,設定一個授權層(authorization layer)。

"客戶端"不能直接登入"服務提供商",只能登入授權層,以此將使用者與客戶端區分開來。

"客戶端"登入授權層所用的令牌(token),與使用者的密碼不同。使用者可在登入時,指定授權層令牌的許可權範圍和有效期。

"客戶端"登入授權層以後,"服務提供商"根據令牌的許可權範圍和有效期,向"客戶端"開放使用者儲存的資料

OAuth 2.0的執行流程

(A)使用者開啟客戶端,客戶端要求使用者給予授權。

(B)使用者同意給予客戶端授權。

(C)客戶端使用上一步獲得的授權(一般是Code),向認證伺服器申請令牌TOKEN。

(D)認證伺服器對客戶端進行認證以後,確認無誤,同意發放令牌

(E)客戶端使用令牌,向資源伺服器申請獲取資源(使用者資訊等)

(F)資源伺服器確認令牌無誤,同意向客戶端開放資源。

重點是如何獲取Token

客戶端獲取授權的五種模式:

客戶端必須得到使用者的授權(authorization grant),才能獲得令牌(access token)。

OAuth 2.0定義了五種授權方式:

  • 授權碼模式(authorization code)
  • 簡化模式(implicit)
  • 密碼模式(resource owner password credentials)
  • 客戶端模式(client credentials)
  • 擴充套件模式(Extension)

1.授權碼模式(authorization code):

功能最完整、流程最嚴密的授權模式

特點是通過客戶端的後臺伺服器,與"服務提供商"的認證伺服器進行互動。

以微信公眾平臺公眾號網頁應用開發流程為例。步驟如下:

(A)使用者訪問客戶端,客戶端將使用者導向認證伺服器。

(B)使用者選擇是否給予客戶端授權。

(C)若使用者給予授權,認證伺服器將使用者導向客戶端指定的"重定向URI"(redirection URI),同時附上授權碼code。

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

(E)認證伺服器核對了授權碼和重定向URI,確認無誤後,向客戶端傳送訪問令牌(access token)和更新令牌(refresh token)

一些重要引數:

  • response_type:表示授權型別,必選項,此處的值固定為"code"
  • appid:表示客戶端的ID,必選項
  • redirect_uri:表示重定向URI,可選項
  • scope:表示申請的許可權範圍,可選項
  • state:表示客戶端的當前狀態,可以指定任意值,認證伺服器會原封不動地返回這個值。用於防止惡意攻擊

1.引導使用者跳轉到授權頁面:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

引數:

appid      公眾號的唯一標識

redirect_uri    授權後重定向的回撥連結地址, 請使用 urlEncode 對連結進行處理

response_type      返回型別,請填寫code

scope     應用授權作用域,有snsapi_base 、snsapi_userinfo 兩種

state       重定向後會帶上state引數,開發者可以填寫a-zA-Z0-9的引數值,最多128位元組

2.通過code獲取Token

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

引數:

appid      公眾號的唯一標識

secret     公眾號的appsecret

code       填寫獲取的code引數(存在有效期,通常設為10分鐘,客戶端只能使用該碼一次,否則會被授權伺服器拒絕。該碼與客戶端ID和重定向URI,是一一對應關係

grant_type     填寫為authorization_code

返回結果:

{

"access_token":"ACCESS_TOKEN", //網頁授權介面呼叫憑證,注意:此access_token與基礎支援的access_token不同

"expires_in":7200,  // access_token介面呼叫憑證超時時間,單位(秒)

"refresh_token":"REFRESH_TOKEN", //使用者重新整理access_token

"openid":"OPENID",  //使用者唯一標識

"scope":"SCOPE"  //使用者授權的作用域,使用逗號(,)分隔

 } 

access_token:表示訪問令牌,必選項。

token_type:表示令牌型別,該值大小寫不敏感,必選項,可以是bearer型別或mac型別。

expires_in:表示過期時間,單位為秒。如果省略該引數,必須其他方式設定過期時間。

refresh_token:表示更新令牌,用來獲取下一次的訪問令牌,可選項。

scope:表示許可權範圍,如果與客戶端申請的範圍一致,此項可省略。

2.簡化模式(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中的令牌。

3.密碼模式(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"

     }

整個過程中,客戶端不得儲存使用者的密碼。

4.客戶端模式(Client Credentials Grant)

指客戶端以自己的名義,而不以使用者的名義,向"服務提供商"進行認證。嚴格地說,客戶端模式並不屬於OAuth框架所要解決的問題。在這種模式中,使用者直接向客戶端註冊,客戶端以自己的名義要求"服務提供商"提供服務,其實不存在授權問題。

步驟如下:

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

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

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

  • granttype:表示授權型別,此處的值固定為"clientcredentials",必選項。
  • 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"

     }

5.擴充套件模式Extension

擴充套件模式,是一種自定義模式。規範中僅對“grant type”引數提出了須為URI的要求。對於其他申請資料,可以根據需求進行自定義。

附規範例子。

     POST /token HTTP/1.1

     Host: server.example.com

     Content-Type: application/x-www-form-urlencoded

     grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml2-

     bearer&assertion=PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU

     [...omitted for brevity...]aG5TdGF0ZW1lbnQ-PC9Bc3NlcnRpb24-

更新令牌

如果使用者訪問的時候,客戶端的"訪問令牌"已經過期,則需要使用"更新令牌"申請一個新的訪問令牌。

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

  • granttype:表示使用的授權模式,此處的值固定為"refreshtoken",必選項。
  • 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