1. 程式人生 > >OAuth2.0 協議入門指南

OAuth2.0 協議入門指南

本文希望以應用場景的角度出發,幫助大家快隨瞭解OAuth協議流程,更為清楚明白的介紹在各種情況使用什麼授權模式更為合適。
OAuth2 官網
原文地址
本系列相關文章:
OpenID Connect 協議入門指南
SAML2.0入門指南

1. 協議中各種角色:應用、API和使用者

第三方應用:客戶端
客戶端,即嘗試去獲得使用者賬號資訊的應用,使用者需要先對此操作授權。

API: 資源伺服器
即資源伺服器,提供用來獲得使用者資訊的API。

授權伺服器
授權伺服器用來提供介面,讓使用者同意或者拒接訪問請求。在某些情況下,授權伺服器和API資源伺服器會是同一個,但是在大多數情況下,二者是獨立的。

使用者:資源的擁有者


資源的擁有者,當前的請求正在嘗試獲得他們賬戶的部分資訊。

2. 建立App

在開始OAuth流程之前,你首選需要註冊一個新應用到伺服器。通常在註冊的過程中,需要提供應用的基本資訊,比如應用名稱、網站資訊、logo等等。此外,你還需要註冊一個重定向URI,用以將使用者通過瀏覽器或者移動客戶端重定向回Web伺服器,這個URI很重要,在後面的我們會具體講到

2.1 重定向URI

伺服器只會把使用者重定向回註冊過的URI以避免一些安全攻擊。任何HTTP的從定向請求都必須使用TLS保護,所以要求使用HTTPS。這樣的要求是為了防止token在傳輸的過程中被截獲。對於原生APP,重定向的URI可以被註冊為一個自定義的URL scheme,比如

2.2 Client ID & Secret

當註冊完畢之後,一般會返回給使用者一個客戶端ID(Client ID)和一個客戶端金鑰(Client Secret)。這個ID一般是公開的資訊,用來構造登入URL,或者被包含在頁面的JS程式碼中。這個金鑰(Secret) 必須是保密的。如果一個已經部署的應用不能保護金鑰,比如一個簡單的JS網頁,則不應該使用客戶端金鑰,同時理論上伺服器也不應該向這類應用頒發金鑰。

3. 授權:得到授權碼

OAuth 2流程的第一步是獲得使用者的授權。對於基於瀏覽器應用或是移動應用,這一步通常是在伺服器顯示給使用者的介面上完成。

OAuth 2提供了多種授權模式(grant types

),根據不同的情況而使用。

  • 授權碼模式:適用於Web應用、瀏覽器應用或是移動APP;
  • 口令模式:適用於使用使用者名稱和口令登入的模式;
  • 應用訪問模式:適用於應用訪問;
  • 預設模式:之前被推薦在沒有Secret情況下使用,現在被沒有客戶端金鑰的授權碼模式取代。

每一個模式的使用細節將在下面的章節中說明。

3.1 Web服務

Web服務是最常見的應用型別。使用者所使用的Web App程式執行在伺服器端,其原始碼不會公開暴露,這就代表著這類應用在授權的過程中可以使用客戶端金鑰(Client Secret),以避免某些攻擊手段。

3.1.1 授權

建立登入連結,將使用者重定向到授權伺服器:

https://oauth2server.com/auth?response_type=code&
 client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=1234zyx
  • code: 代表伺服器希望收到授權碼;
  • client_id: 註冊應用時頒發的ID;
  • redirect_uri: 指明當使用者授權完成之後返回的地址;
  • scope: 一個或多個值,用來指明希望獲得使用者賬戶哪部分許可權;
  • state:由應用生成的一個隨機字串,會在稍後的過程中去驗證。

通過以上的連結,使用者將會看到如下的介面

image.png

當用戶點選“Allow”之後,授權伺服器會把使用者重定向迴應用網站,並在連結中帶上授權碼:

https://oauth2client.com/cb?code=AUTH_CODE_HERE&state=1234zyx
  • code: 伺服器返回的授權碼;
  • state: 返回請求授權碼過程中傳送的state;

當應有接收到這個請求時,要首先驗證state是否就是應用剛才傳送的值。在傳送state之後,可以把state儲存到Session以便於後續的比較。這樣做的目的是防止應用接受任意偽造的授權碼。

3.1.2 換取Token

然後使用授權碼到資源伺服器換取Token:

POST https://api.oauth2server.com/token
  grant_type=authorization_code&
  code=AUTH_CODE_HERE&
  redirect_uri=REDIRECT_URI&
  client_id=CLIENT_ID&
  client_secret=CLIENT_SECRET
  • grant_type=authorization_code - 代表授權模式為驗證碼;
  • code=AUTH_CODE_HERE - 驗證碼;
  • redirect_uri=REDIRECT_URI - 重定向URI;
  • **client_id=CLIENT_ID **- 註冊應用時頒發的ID;
  • client_secret=CLIENT_SECRET - 客戶端金鑰,因為當前請求時伺服器之間傳輸的,並沒有暴露給使用者。

API伺服器會返回授權碼和其有效期:

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600
}

或者是授權失敗的提示:

{
  "error":"invalid_request"
}

安全性提示:伺服器要求應用必須提前註冊從定向URI

3.2 純頁面應用

純頁面應用,也稱為瀏覽器應用,其所有執行程式碼都會載入到本地的瀏覽器上。因此其程式碼會暴露給使用者的瀏覽器,不能保護客戶端金鑰的安全,所以客戶端金鑰不能在這種情況下使用,除此之外其和Web應用沒有太大區別。

以前,曾經推薦使用預設模式(implicit type),該種模式將會直接返回token,並不使用授權碼來換取token。但是到了本文編寫之時,業界已經開始轉為推薦使用沒有Scret的授權碼流程,這樣這樣協議流程更為安全,具體內容請見引文: Redhat, Deutsche Telekom, Smart Health IT.

3.2.1 授權

建立登入連結,將使用者傳送至授權伺服器:

https://oauth2server.com/auth?response_type=code&
client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=1234zyx
  • code - 指明使用授權碼模式;
  • client_id - 註冊時頒發的client ID;
  • redirect_uri - 重定向URI,代表當授權完成之後,返回的路徑;
  • scope - 一個或多個值,代表所希望訪問當前使用者的那部分資訊;
  • state - 由於後續步驟驗證實用的隨機字串。
    之後,同樣使用者會顯示授權頁面:

    image.png


    當用戶點選“Allow”,授權伺服器依據重定向URI將使用者返回到應用網站:
https://oauth2client.com/cb?code=AUTH_CODE_HERE&state=1234zyx
  • code - 授權伺服器返回的授權碼;
  • state - 登入請求中發出的隨機碼;

應有伺服器收到該請求之後,應該先核對state的值,以避免接受偽造的授權碼;

3.2.2 換取Token

POST https://api.oauth2server.com/token
  grant_type=authorization_code&
  code=AUTH_CODE_HERE&
  redirect_uri=REDIRECT_URI&
  client_id=CLIENT_ID
  • grant_type=authorization_code - 代表授權模式為驗證碼;
  • code=AUTH_CODE_HERE - 驗證碼;
  • redirect_uri=REDIRECT_URI - 重定向URI;
  • **client_id=CLIENT_ID **- 註冊應用時頒發的ID;

3.3 移動APP

以前,曾經推薦使用預設模式(implicit type),該種模式將會直接返回token,並不使用授權碼來換取token。但是到了本文編寫之時,業界已經開始轉為推薦使用沒有Scret的授權碼流程,這樣這樣協議流程更為安全,

類似於純頁面應用,移動應用不能包含客戶端金鑰,所以使用的是沒有客戶端金鑰的Oauth流程。此外,對於移動APP,還有一些特別地方需要注意。

3.3.1 授權

建立一個登陸按鈕,將使用者跳轉到伺服器在手機上原生APP,或是通過手機的瀏覽器跳轉到伺服器Web頁面、無論是IOS還是Android,都可以通過URL Scheme協議啟動本地APP;

3.3.1.1 使用伺服器的APP

如果使用者安裝了伺服器的原生APP,比如微博APP或是微信APP,可以通過URL來直接啟動APP:

fbauth2://authorize?response_type=code&client_id=CLIENT_ID
  &redirect_uri=REDIRECT_URI&scope=email&state=1234zyx
  • code - 指明使用授權碼模式;
  • client_id - 註冊時頒發的client ID;
  • redirect_uri - 重定向URI,代表當授權完成之後,返回的路徑;
  • scope - 一個或多個值,代表所希望訪問當前使用者的那部分資訊;
  • state - 由於後續步驟驗證實用的隨機字串。

對於還要支援PKCE extension的伺服器,還需要建立一個隨機字串("code verifier")儲存本地,然後再URL中追加如下引數:

  • code_challenge=XXXXXXX - 過base64編碼後的"code verifier"的Hash值;
  • code_challenge_method=S256 - 指明Hash演算法種類,這裡是sha256;

需要說明的是,這裡的URL用的協議App提前向作業系統定義好的。

3.3.1.2 使用手機Web瀏覽器

如果伺服器在手機上沒有一個原生的APP,也可以通過手機瀏覽器上來走標準的Web認證流程。這裡需要注意的是,不要使用應用內建的WebView,因為這樣就不無法保證使用者正在登陸網站是不是偽造的。

一般是使用移動端的原生瀏覽器,對於IOS 9+版本的使用者,可以使用“SafariViewController”在應用中啟動嵌入瀏覽器,這個API會顯示位址列讓使用者判斷是否開啟正確的網頁,同時還提供和Safari瀏覽器共享cookie的功能。該API能保證應用被注入和修改,所以可以被認為是安全的。對於Android開發者,可以考慮使用Chrome Custom Tabs來提供類似的功能。

https://facebook.com/dialog/oauth?response_type=code&client_id=CLIENT_ID
 &redirect_uri=REDIRECT_URI&scope=email&state=1234zyx

引數的意義和使用伺服器原生APP的情況是一樣的。比如使用者登入FaceBook,就會在手機上看到如下介面:

everyday-city-auth.png

3.3.2 換取Token

當用戶點選"Approve"之後,使用者將會被重定向到應用,同樣可以使用URL Scheme:

fb00000000://authorize#code=AUTHORIZATION_CODE&state=1234zyx

應用收到該請求之後,要先比較state的值是否滿足預期,然後用授權碼來換取Token。

換取Token的過程和在Web中請求類似,只不過沒有加入Client Secret。如果伺服器需要支援PKCE,則還需要新增更多的引數:

POST https://api.oauth2server.com/token
  grant_type=authorization_code&
  code=AUTH_CODE_HERE&
  redirect_uri=REDIRECT_URI&
  client_id=CLIENT_ID&
  code_verifier=VERIFIER_STRING
  • grant_type=authorization_code - 標識這是授權碼模式;
  • code=AUTH_CODE_HERE - 授權碼;
  • redirect_uri=REDIRECT_URI -重定向URL;
  • client_id=CLIENT_ID - Client ID;
  • code_verifier=VERIFIER_STRING - 之前步驟中,生成的隨機字串

如果伺服器支援PKCE,則授權伺服器需要能“Code-Challenge”中識別code,也就是提供再次對code_verifier進行Hash,並且比較計算出的Hash值和之前的code_challenge是否一致,以此代替Client Secret,保證安全性。

3.4 其他授權模式

3.4.1 口令模式

這種模式直接使用使用者名稱和口令來取回Token。很顯然,這要求應用去收集使用者的口令,所以只建議當前的APP是專門為伺服器設計的情況下使用。比如Twitter的App使用該模式登入。

POST https://api.oauth2server.com/token
  grant_type=password&
  username=USERNAME&
  password=PASSWORD&
  client_id=CLIENT_ID
  • grant_type=password - 指明使用口令模式;
  • username=USERNAME - 使用者名稱;
  • password=PASSWORD - 口令;
  • client_id=CLIENT_ID - client ID;

資源伺服器返回的Token和其他模式是一樣的。值得注意的是,因為口令模式多用於移動端和桌面應用,使用Secret並不合適

3.4.2 應用訪問模式

在一些情況下,是應用去訪問服務區獲取資源,而不是某個使用者。比如應用去獲取一些服務在應用配置資訊,這些資訊不屬於某個使用者的。在這種情形下,應用也需要被授權,得到Token去訪問資料,這就是應用訪問模式的意義。

OAuth提供了client_credentials模式來結局這個問題:

POST https://api.oauth2server.com/token
    grant_type=client_credentials&
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET

資源伺服器返回形式和其他模式是相同的。

4. 建立已經授權的請求

最後就是使用Token獲取資源,如何表面一個請求是已經唄授權?就是Http的頭中加入Token:

curl -H "Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia" \
https://api.oauth2server.com/1/me

另外還要確保是使用HTTPS通訊,這樣才能確保資訊保安。

5. 與OAuth 1.0版本的差異

最後說明下兩個版本的OAuth協議有什麼不同點。

5.1 認證和簽名

OAuth 1.0 流程中有大量密碼學上的簽名操作,以保證資料完整性;OAuth 2中有HTTPS來保護資料。

5.2 使用者體驗

和OAuth 1.0相比,OAuth 2在移動端的體驗更好。

5.3 效能

和OAuth 1.0相比,OAuth 2效能更好,減少了流程的步驟。

其他參考



作者:登高且賦
連結:https://www.jianshu.com/p/6392420faf99
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。