更友好的閱讀體驗,請轉至 OAuth 深入介紹 。 1. 前言 2. OAuth2 角色 2.1 資源所有者(Resource Owner) 2.2 資源/授權伺服器(Resource/Authorization Server) 2.3 客戶端(Client) 3. OAuth 2 的授權流程 4. ...
更友好的閱讀體驗,請轉至 OAuth 深入介紹 。
- 1. 前言
- 2. OAuth2 角色
- 3. OAuth 2 的授權流程
- 4. 客戶端應用註冊
- 5. 授權許可(Authorization Grant)
- 6. 總結
- 參考資料及文獻
- 名詞中英文對照
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 的角色有了些概念,接下來讓我們來看看這幾個角色之間的抽象授權流程圖和相關解釋。
請註意,實際的授權流程圖會因為用戶返回授權許可類型的不同而不同。但是下圖大體上能反映一次完整抽象的授權流程。
- Authrization Request
客戶端向用戶請求對資源伺服器的authorization grant
。 - Authorization Grant(Get)
如果用戶授權該次請求,客戶端將收到一個authorization grant
。 - Authorization Grant(Post)
客戶端向授權伺服器發送它自己的客戶端身份標識和上一步中的authorization grant
,請求訪問令牌。 - Access Token(Get)
如果客戶端身份被認證,並且authorization grant
也被驗證通過,授權伺服器將為客戶端派發access token
。授權階段至此全部結束。 - Access Token(Post && Validate)
客戶端向資源伺服器發送access token
用於驗證並請求資源信息。 - 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 id
和client secret
的形式為應用發佈client credentials
(客戶端憑證)。client id
是公開透明的字元串,授權方服務使用該字元串來標識應用程式,並且還用於構建呈現給用戶的授權 url 。當應用請求訪問用戶的帳戶時,client secret
用於驗證應用身份,並且必須在客戶端和服務之間保持私有性。
5. 授權許可(Authorization Grant)
如上文的抽象授權流程圖所示,前四個階段包含了獲取authorization grant
和access 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
地址,並附帶code
和state
參數(由之前客戶端提供),於是客戶端便能直接讀取到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 id
和client 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 更改為 token 或 id_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_type的response_type
參數值為 token 或 id_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_token
(access 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)理論還沒有引出,希望在之後的日子里能帶來更多關於鑒權相關的博文,如認證體系和功能許可權設計在工程上的應用,共勉。
學習和編程都是快樂的。
參考資料及文獻
- The OAuth 2.0 Authorization Framework
- What is the OAuth 2.0 Authorization Code Grant Type?
- An Introduction to OAuth 2
- Implicit Flow
- Response Properties
- 認證授權 OAuth2授權
名詞中英文對照
英文 | 中文 |
---|---|
Authorization Grant | 授權許可 |
Authorization Code | 授權碼 |
Access Token | 訪問令牌 |
Authorization | 授權 |
Authentication | 認證 |