認證授權:學習OAuth協議


前言:

  上一篇文章介紹了QQ一鍵登錄的過程,接下來我們就來探究其背后的原理

1、什么是OAuth協議?

  OAuth2是一種授權標准框架,用來解決的是第三方服務在無需用戶提供賬號密碼的情況下訪問用戶的私有資源的一套流程規范。同時,任何第三方都可以使用OAuth認證服務,任何服務提供商都可以實現自身的OAuth認證服務,因而OAuth是開放的。業界提供了OAuth的多種實現如PHP、JavaScript,Java,Ruby等各種語言開發包,大大節約了程序員的時間,因而OAuth是簡易的。互聯網很多服務如Open API,很多大公司如Google,Yahoo,Microsoft等都提供了OAuth認證服務,這些都足以說明OAuth標准逐漸成為開放資源授權的標准。

  目前最新版本為OAuth2.0,主要參考材料為RFC 6749

  本文主要介紹OAuth2.0

2、思路和特點

  思路:

   OAuth本質是在"客戶端"與"服務提供商"之間,設置了一個授權層(authorization layer)。"客戶端"不能直接登錄"服務提供商",只能登錄授權層,以此將用戶與客戶端區分開來。"客戶端"登錄授權層所用的令牌(token),與用戶的密碼不同。用戶可以在登錄的時候,指定授權層令牌的權限范圍和有效期。

  特點:  

  (1). 簡單:不管是OAuth服務提供者還是應用開發者,都很易於理解與使用;

(2). 安全:沒有涉及到用戶密鑰等信息,更安全更靈活;

(3). 開放:任何服務提供商都可以實現OAuth,任何軟件開發商都可以使用OAuth;

3、名詞定義

(1)Third-party application:第三方應用程序,下圖中又稱"客戶端"(Client:上一篇文中簡書

(2)Resource Owner:資源所有者,通常為"用戶"(User:上一篇中的QQ用戶)

(3)Authorization Server:認證服務器,即服務提供商專門用來處理認證的服務器。(上一篇文中的QQ互聯服務)

(4)Resource Server:資源服務器,即服務提供商存放用戶生成的資源的服務器。它與認證服務器,可以是同一台服務器,也可以是不同的服務器。(上一篇文中的QQ信息服務)

(5)User Agent:用戶代理,通常指瀏覽器。

(6)HTTP service:HTTP服務提供商

(7)Access Token:訪問令牌,授權后得到的憑證

(8)Refresh Token:刷新令牌是用於獲取訪問令牌的憑據。

 4、運行流程

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

  

步驟詳解:(對應上圖步驟)

(A)用戶打開客戶端以后,客戶端要求用戶給予授權。 (B)用戶同意給予客戶端授權。 (C)客戶端使用上一步獲得的授權,向認證服務器申請令牌。 (D)認證服務器對客戶端進行認證以后,確認無誤,同意發放令牌。 (E)客戶端使用令牌,向資源服務器申請獲取資源。 (F)資源服務器確認令牌無誤,同意向客戶端開放受保護的資源。

  可以看出,上面步驟中,(B)是關鍵,即用戶怎樣給客戶端授權。有了這個授權以后,客戶端就可以獲取令牌,進而憑令牌獲取資源。

  下面我們來講解OAuth提供的4種授權方式。

5、客戶端授權模式:

   客戶端必須得到用戶的授權(authorization grant),才能獲得令牌(access token)最后才能憑令牌獲取受保護的資源

   OAuth 2.0定義了四種授權方式和刷新Token

    • 授權碼模式(Authorization Code)
    • 隱式模式(Implicit Grant )
    • 密碼模式(Resource Owner Password Credentials)
    • 客戶端模式(Client Credentials)
    • 刷新令牌(Refresh Token

  5.1 授權碼模式(Authorization Code):

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

    

步驟如下:

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

  例子:https://graph.qq.com/oauth2.0/show?which=Login&display=pc&client_id=100410602&redirect_uri=http%3A%2F%2Fwww.jianshu.com%2Fusers%2Fauth%2Fqq_connect%2Fcallback&response_type=code&state=%257B%257D

  參數:

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

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

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

  例子:http://www.jianshu.com/users/auth/qq_connect/callback?code=B36BD11F2DF8ED948F8CDE81CDDD0EEB&state=%257B%257D

  參數:    

    • code:表示授權碼,必選項。該碼的有效期應該很短,通常設為10分鍾,客戶端只能使用該碼一次,否則會被授權服務器拒絕。該碼與客戶端ID和重定向URI,是一一對應關系。
    • state:表示客戶端的當前狀態,可以指定任意值,認證服務器會原封不動地返回這個值。這用於防止CSRF攻擊

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

  例子:https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=[YOUR_APP_ID]&client_secret=[YOUR_APP_Key]&code=[The_AUTHORIZATION_CODE]&redirect_uri=[YOUR_REDIRECT_URI]

  參數:  

    • grant_type:表示使用的授權模式,必選項,此處的值固定為"authorization_code"。
    • code:表示上一步獲得的授權碼,必選項。
    • redirect_uri:表示重定向URI,必選項,且必須與A步驟中的該參數值保持一致。
    • client_id:表示客戶端ID,必選項。

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

  例子:    

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

{ "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", "token_type":"bearer", "expires_in":3600, "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk", "scope":"create delete"}

參數使用JSON格式發送(Content-Type: application/json)。此外,HTTP頭信息中明確指定不得緩存

  說明:

    • access_token:表示訪問令牌,必選項。
    • token_type:表示令牌類型,該值大小寫不敏感,必選項,可以是bearer類型或mac類型。
    • expires_in:表示過期時間,單位為秒。如果省略該參數,必須其他方式設置過期時間。
    • refresh_token:表示更新令牌,用來獲取下一次的訪問令牌,可選項。
    • scope:表示權限范圍,如果與客戶端申請的范圍一致,此項可省略。

 

  5.2 簡化模式(Implicit Grant ):

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

    

步驟如下:

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

  例子:

    https://graph.qq.com/oauth2.0/authorize?response_type=token&client_id=[YOUR_APPID]&redirect_uri=[YOUR_REDIRECT_URI]&scope=[THE_SCOPE]

   參數:

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

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

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

   參數:

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

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

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

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

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

 

  5.3 密碼模式(Resource Owner Password Credentials)

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

    在這種模式中,用戶必須把自己的密碼給客戶端,但是客戶端不得儲存密碼。這通常用在用戶對客戶端高度信任的情況下

    

 
         
步驟如下:
(A)用戶向客戶端提供用戶名和密碼。 (B)客戶端將用戶名和密碼發給認證服務器,向后者請求令牌。
  例子:

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

  參數:    
    • grant_type:表示授權類型,此處的值固定為"password",必選項。
    • username:表示用戶名,必選項。
    • password:表示用戶的密碼,必選項。
    • scope:表示權限范圍,可選項。
(C)認證服務器確認無誤后,向客戶端提供訪問令牌。
  結果:

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

{
"access_token":"XXX",
"token_type":"example",
"expires_in":3600,
"refresh_token":"XXX",
"example_parameter":"XXX"
}

 

  5.4 客戶端模式(Client Credentials)

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

     

 
         
步驟如下:
(A)客戶端向認證服務器進行身份認證,並要求一個訪問令牌。
   參數: 
    • granttype:表示授權類型,此處的值固定為"clientcredentials",必選項。
    • scope:表示權限范圍,可選項。
(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.5 刷新令牌(Refresh Token)

     

步驟:
(A)客戶端通過與授權服務器進行身份驗證並提供授權授權來請求訪問令牌。
(B)授權服務器對客戶端進行身份驗證並驗證授權,如果有效,則發出訪問令牌和刷新令牌。
(C)客戶端通過提供訪問令牌向資源服務器發出受保護的資源請求
(D)資源服務器驗證訪問令牌,如果有效,則為請求提供服務結果
(E)重復步驟(C)和(D),直到訪問令牌過期。如果客戶機知道訪問令牌已過期,它將跳到步驟(G);否則,它將發出另一個受保護資源請求。
(F)由於訪問令牌無效,資源服務器返回無效令牌錯誤。
(G)客戶端通過向授權服務器進行身份驗證並顯示刷新令牌來請求新的訪問令牌。客戶端身份驗證要求基於客戶端類型和授權服務器策略。
  例子:
    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
  參數: 
    • granttype:表示使用的授權模式,此處的值固定為"refreshtoken",必選項。
    • refresh_token:表示早前收到的更新令牌,必選項。
    • scope:表示申請的授權范圍,不可以超出上一次申請的范圍,如果省略該參數,則表示與上一次一致。
(H)授權服務器對客戶端進行身份驗證並驗證刷新令牌,如果有效,則發出新的訪問令牌(以及新刷新令牌)。

6、JSON Web Token (JWT)

  JWT是一個定義一種緊湊的自包含的並且提供防篡改機制的傳遞數據的方式的標准協議。

  如下示例:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

  上面示例看着復雜,其實 JWT由3部分構成:header.payload.signature,每個部分由“.”來分割開來。

 6.1 Header

  header是一個有效的JSON,其中通常包含了兩部分:token類型和簽名算法。

{
  "alg": "HS256",
  "typ": "JWT"
}

  對這個JSON采用base64編碼后就是第1部分eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

 6.2 Payload

  這一部分代表真正想要傳遞的數據,包含一組Claims,其中JWT預定義了一些Claim后面會介紹。

{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}

  對JSON采用base64編碼后就是第2部分eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

 6.3 Signature

  這一部分是可選的,由於前面Header和Payload部分是明文的信息,所以這一部分的意義在於保障信息不被篡改用的,生成這部分的方式如下:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

  token生成方使用header中指定的簽名算法對“header.payload”部分進行簽名,得到的第3部分SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c,然后組合成一個完整的JWT字符串 . 而token消費方在拿到token后, 使用同樣的簽名算法來生成簽名,用來判斷header和payload部分有沒有被篡改過,因為簽名的密鑰是只有通信雙方知道的,所以可以保證這部分信息不被第三方所篡改。

 6.4 JWT的一些Claims

JWT規范中預先定義了一些Cliam,但並不是必選的,常用的有:

  • iss(Issuer簽發者)
  • sub(subject簽發給的受眾,在Issuer范圍內是唯一的)
  • aud(Audience接收方)
  • exp(Expiration Time過期時間)
  • iat(Issued At簽發時間)等等。

后續:

  后續將繼續介紹認證授權-中ODIC的內容

引用:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM