OAuth 2 深入介紹


更友好的閱讀體驗,請轉至 OAuth 深入介紹

1. 前言

OAuth 2 是一個授權框架,或稱授權標准,它可以使第三方應用程序或客戶端獲得對HTTP服務上(例如 Google,GitHub )用戶帳戶信息的有限訪問權限。OAuth 2 通過將用戶身份驗證委派給托管用戶帳戶的服務以及授權客戶端訪問用戶帳戶進行工作。綜上,OAuth 2 可以為 Web 應用 和桌面應用以及移動應用提供授權流程。

本文將從OAuth 2 角色,授權許可類型,授權流程等幾方面進行講解。

在正式講解之前,這里先引入一段應用場景,用以與后文的角色講解對應。

開發者A注冊某IT論壇后,發現可以在信息欄中填寫自己的 Github 個人信息和倉庫項目,但是他又覺得手工填寫十分麻煩,直接提供 Github 賬戶和密碼給論壇管理員幫忙處理更是十分智障。
不過該論壇似乎和 Github 有不可告人的秘密,開發者A可以點擊“導入”按鈕,授權該論壇訪問自己的 Github 賬戶並限制其只具備讀權限。這樣一來, Github 中的所有倉庫和相關信息就可以很方便地被導入到信息欄中,賬戶隱私信息也不會泄露。
這背后,便是 OAuth 2 在大顯神威。

2. OAuth2 角色

OAuth 2 標准中定義了以下幾種角色:

  • 資源所有者(Resource Owner)
  • 資源服務器(Resource Server)
  • 授權服務器(Authorization Server)
  • 客戶端(Client)

2.1 資源所有者(Resource Owner)

資源所有者是 OAuth 2 四大基本角色之一,在 OAuth 2 標准中,資源所有者即代表授權客戶端訪問本身資源信息的用戶(User),也就是應用場景中的“開發者A”。客戶端訪問用戶帳戶的權限僅限於用戶授權的“范圍”(aka. scope,例如讀取或寫入權限)。

如果沒有特別說明,下文中出現的"用戶"將統一代表資源所有者。

2.2 資源/授權服務器(Resource/Authorization Server)

資源服務器托管了受保護的用戶賬號信息,而授權服務器驗證用戶身份然后為客戶端派發資源訪問令牌。

在上述應用場景中,Github 既是授權服務器也是資源服務器,個人信息和倉庫信息即為資源(Resource)。而在實際工程中,不同的服務器應用往往獨立部署,協同保護用戶賬戶信息資源。

2.3 客戶端(Client)

在 OAuth 2 中,客戶端即代表意圖訪問受限資源的第三方應用。在訪問實現之前,它必須先經過用戶者授權,並且獲得的授權憑證將進一步由授權服務器進行驗證。

如果沒有特別說明,下文中將不對"應用",“第三方應用”,“客戶端”做出區分。

3. OAuth 2 的授權流程

目前為止你應該對 OAuth 2 的角色有了些概念,接下來讓我們來看看這幾個角色之間的抽象授權流程圖和相關解釋。

請注意,實際的授權流程圖會因為用戶返回授權許可類型的不同而不同。但是下圖大體上能反映一次完整抽象的授權流程。

  1. Authrization Request
    客戶端向用戶請求對資源服務器的authorization grant
  2. Authorization Grant(Get)
    如果用戶授權該次請求,客戶端將收到一個authorization grant
  3. Authorization Grant(Post)
    客戶端向授權服務器發送它自己的客戶端身份標識和上一步中的authorization grant,請求訪問令牌。
  4. Access Token(Get)
    如果客戶端身份被認證,並且authorization grant也被驗證通過,授權服務器將為客戶端派發access token。授權階段至此全部結束。
  5. Access Token(Post && Validate)
    客戶端向資源服務器發送access token用於驗證並請求資源信息。
  6. Protected Resource(Get)
    如果access token驗證通過,資源服務器將向客戶端返回資源信息。

4. 客戶端應用注冊

在應用 OAuth 2 之前,你必須在授權方服務中注冊你的應用。如 Google Identity Platform 或者 Github OAuth Setting,諸如此類 OAuth 實現平台中一般都要求開發者提供如下所示的授權設置項。

  • 應用名稱
  • 應用網站
  • 重定向URI或回調URL

重定向URI是授權方服務在用戶授權(或拒絕)應用程序之后重定向供用戶訪問的地址,因此也是用於處理授權碼或訪問令牌的應用程序的一部分。

4.1 Client ID 和 Client Secret

一旦你的應用注冊成功,授權方服務將以client idclient secret的形式為應用發布client credentials(客戶端憑證)。client id是公開透明的字符串,授權方服務使用該字符串來標識應用程序,並且還用於構建呈現給用戶的授權 url 。當應用請求訪問用戶的帳戶時,client secret用於驗證應用身份,並且必須在客戶端和服務之間保持私有性。

5. 授權許可(Authorization Grant)

如上文的抽象授權流程圖所示,前四個階段包含了獲取authorization grantaccess token的動作。授權許可類型取決於應用請求授權的方式和授權方服務支持的 Grant Type。OAuth 2 定義了四種 Grant Type,每一種都有適用的應用場景。

  • Authorization Code
    結合普通服務器端應用使用。
  • Implicit
    結合移動應用或 Web App 使用。
  • Resource Owner Password Credentials
    適用於受信任客戶端應用,例如同個組織的內部或外部應用。
  • Client Credentials
    適用於客戶端調用主服務API型應用(比如百度API Store)

以下將分別介紹這四種許可類型的相關授權流程。

5.1 Authorization Code Flow

Authorization Code 是最常使用的一種授權許可類型,它適用於第三方應用類型為server-side型應用的場景。Authorization Code授權流程基於重定向跳轉,客戶端必須能夠與User-agent(即用戶的 Web 瀏覽器)交互並接收通過User-agent路由發送的實際authorization code值。

1. User Authorization Request

首先,客戶端構造了一個用於請求authorization code的URL並引導User-agent跳轉訪問。

https://authorization-server.com/auth
 ?response_type=code
 &client_id=29352915982374239857
 &redirect_uri=https%3A%2F%2Fexample-client.com%2Fcallback
 &scope=create+delete
 &state=xcoiv98y2kd22vusuye3kch
  • response_type=code
    此參數和參數值用於提示授權服務器當前客戶端正在進行Authorization Code授權流程。
  • client_id
    客戶端身份標識。
  • redirect_uri
    標識授權服務器接收客戶端請求后返回給User-agent的跳轉訪問地址。
  • scope
    指定客戶端請求的訪問級別。
  • state
    由客戶端生成的隨機字符串,步驟2中用戶進行授權客戶端的請求時也會攜帶此字符串用於比較,這是為了防止CSRF攻擊。

2. User Authorizes Applcation

當用戶點擊上文中的示例鏈接時,用戶必須已經在授權服務中進行登錄(否則將會跳轉到登錄界面,不過 OAuth 2 並不關心認證過程),然后授權服務會提示用戶授權或拒絕應用程序訪問其帳戶。以下是授權應用程序的示例:

3. Authorization Code Grant

如果用戶確認授權,授權服務器將重定向User-agent至之前客戶端提供的指向客戶端的redirect_uri地址,並附帶codestate參數(由之前客戶端提供),於是客戶端便能直接讀取到authorization code值。

https://example-client.com/redirect
 ?code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3
 &state=xcoiv98y2kd22vusuye3kch

state值將與客戶端在請求中最初設置的值相同。客戶端將檢查重定向中的狀態值是否與最初設置的狀態值相匹配。這可以防止CSRF和其他相關攻擊。

code是授權服務器生成的authorization code值。code相對較短,通常持續1到10分鍾,具體取決於授權服務器設置。

4. Access Token Request

現在客戶端已經擁有了服務器派發的authorization code,接下來便可以使用authorization code和其他參數向服務器請求access token(POST方式)。其他相關參數如下:

  • grant_type=authorization_code - 這告訴服務器當前客戶端正在使用Authorization Code授權流程。
  • code - 應用程序包含它在重定向中給出的授權碼。
  • redirect_uri - 與請求authorization code時使用的redirect_uri相同。某些資源(API)不需要此參數。
  • client_id - 客戶端標識。
  • client_secret - 應用程序的客戶端密鑰。這確保了獲取access token的請求只能從客戶端發出,而不能從可能截獲authorization code的攻擊者發出。

5. Access Token Grant

服務器將會驗證第4步中的請求參數,當驗證通過后(校驗authorization code是否過期,client idclient secret是否匹配等),服務器將向客戶端返回access token

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

至此,授權流程全部結束。直到access token 過期或失效之前,客戶端可以通過資源服務器API訪問用戶的帳戶,並具備scope中給定的操作權限。

5.2 Implicit Flow

Implicit授權流程和Authorization Code基於重定向跳轉的授權流程十分相似,但它適用於移動應用和 Web App,這些應用與普通服務器端應用相比有個特點,即client secret不能有效保存和信任。

相比Authorization Code授權流程,Implicit去除了請求和獲得authorization code的過程,而用戶點擊授權后,授權服務器也會直接把access token放在redirect_uri中發送給User-agent(瀏覽器)。 同時第1步構造請求用戶授權 url 中的response_type參數值也由 code 更改為 tokenid_token

1. User Authorization Request

客戶端構造的URL如下所示:

https://{yourOktaDomain}.com/oauth2/default/v1/authorize?client_id=0oabv6kx4qq6
h1U5l0h7&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%3
A8080&state=state-296bc9a0-a2a2-4a57-be1a-d0e2fd9bb601&nonce=foo'

response_typeresponse_type參數值為 tokenid_token 。其他請求參數與Authorization Code授權流程相比沒有並什么變化。

2. User Authorizes Application(略)

3. Redirect URI With Access Token In Fragment

假設用戶授予訪問權限,授權服務器將User-agent(瀏覽器) 重定向回客戶端使用之前提供的redirect_uri。並在 uri 的 #fragment 部分添加access_token鍵值對。如下所示:

http://localhost:8080/#access_token=eyJhb[...]erw&token_type=Bearer&expires_in=3600&scope=openid&state=state-296bc9a0-a2a2-4a57-be1a-d0e2fd9bb601
  • token_type - 當且僅當response_type設置為 token 時返回,值恆為 Bearer

注意在Implicit流程中,access_token值放在了 URI 的 #fragment 部分,而不是作為 ?query 參數。

4. User-agent Follows the Redirect URI

User-agent(瀏覽器)遵循重定向指令,請求redirect_uri標識的客戶端地址,並在本地保留 uri 的 #fragment 部分的access_token信息

5. Application Sends Access Token Extraction Script

客戶端生成一個包含 token 解構腳本的 Html 頁面,這個頁面被發送給User-agent(瀏覽器),執行腳本解構完整的redirect_uri並提取其中的access_tokenaccess token信息在第4步中已經被User-agent保存)。

6. Access Token Passed to Application

User-agent(瀏覽器)向客戶端發送解構提取的access token

至此,授權流程全部結束。直到access token 過期或失效之前,客戶端可以通過資源服務器API訪問用戶的帳戶,並具備scope中給定的操作權限。

5.3 Resource Owner Password Credentials Flow

Resource Owner Password Credentials授權流程適用於用戶與客戶端具有信任關系的情況,例如設備操作系統或同一組織的內部及外部應用。用戶與應用交互表現形式往往體現為客戶端能夠直接獲取用戶憑據(用戶名和密碼,通常使用交互表單)。

1. Resource Owner Password Credentials From User Input

用戶向客戶端提供用戶名與密碼作為授權憑據。

2. Resource Owner Password Credentials From Client To Server

客戶端向授權服務器發送用戶輸入的授權憑據以請求 access token。客戶端必須已經在服務器端進行注冊。

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

3. Access Token Passed to Application

授權服務器對客戶端進行認證並檢驗用戶憑據的合法性,如果檢驗通過,將向客戶端派發 access token>

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"example",
  "expires_in":3600,
  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
  "example_parameter":"example_value"
}

5.4 Client Credentials Flow

Client Credential是最簡單的一種授權流程。客戶端可以直接使用它的client credentials或其他有效認證信息向授權服務器發起獲取access token的請求。

兩步中的請求體和返回體分別如下:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
  • grant_type - 必選項,值恆為 client_credentials
{
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "example_parameter":"example_value"
}

6. 總結

說實在的,筆者已經有很長一段時間沒有好好地分享心得,發表博客,這固然有工作繁忙,學習充實的原因,但確實也是有些懶,既然認識到了,自然就不希望再墮落下去了。

這一年里讀了很多書,做了很多事,雖然自覺在大學時期便接觸了部分項目管理和開發的知識,但是工作后的收獲仍然十分動心。微服務也好,DDD也好,或是具體的數據庫理論和運維工程實踐上筆者也有了更深的認識。而時至今日,筆者覺得自己是又到了重新積淀,重新邁向下一個階段的時候。鑒權服務作為構建健壯微服務必不可少的一環(甚至可以說是第一個工程),所以以 OAuth 2 作為重啟的第一篇。當然 OAuth 2 也仍然只是鑒權體系中的授權理論,更基礎的認證(Authentication)理論還沒有引出,希望在之后的日子里能帶來更多關於鑒權相關的博文,如認證體系和功能權限設計在工程上的應用,共勉。

學習和編程都是快樂的。

參考資料及文獻

  1. The OAuth 2.0 Authorization Framework
  2. What is the OAuth 2.0 Authorization Code Grant Type?
  3. An Introduction to OAuth 2
  4. Implicit Flow
  5. Response Properties
  6. 認證授權 OAuth2授權

名詞中英文對照

英文 中文
Authorization Grant 授權許可
Authorization Code 授權碼
Access Token 訪問令牌
Authorization 授權
Authentication 認證


免責聲明!

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



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