Refinition
OAuth2 是在WEB基礎(chǔ)上發(fā)展出來的一個授權(quán)框架(Authorization Framework),也可以認為它是一套協(xié)議,一套能解決第三方授權(quán)問題的解決方案,優(yōu)勢在于它允許第三方應用在不獲取用戶密碼的情況下,獲得訪問用戶資源(用戶的ID信息等)的有限權(quán)限。
它是如何做到的?下面來解析一下這個協(xié)議。
搞懂這個協(xié)議,需要理解下面幾個部分:
四個核心角色
OAuth2 流程中有四個關(guān)鍵角色:
-
資源所有者 (Resource Owner)
用戶(一般指使用客戶端的人),他擁有受保護資源(一般指他的賬號信息);
-
客戶端 (Client)
一個前端UI應用,方便用戶操作的面板。一般來說客戶端和授權(quán)服務器是前后端關(guān)系。
-
授權(quán)服務器 (Authorization Server)
它擁有客戶信息,比如登錄賬號密碼信息,客戶的身份信息等。
它可以驗證用戶身份,并頒發(fā)令牌。
-
資源服務器 (Resource Server)
一般指可以提供給用戶使用的服務器,能給用戶提供專屬服務,比如網(wǎng)盤服務、點外賣服務,這種也叫第三方應用。
資源服務器一般需要用戶信息,才能提供服務。
獲得用戶信息,可以讓用戶注冊,但是APP太多了,很多用戶不愿意注冊了。就發(fā)展出第三方應用去授權(quán)服務器拿取用戶ID的免注冊模式。
四類常見授權(quán)模式
OAuth2 定義了多種授權(quán)方式,適應不同場景,下面看4個常見:
- 授權(quán)碼模式 (Authorization Code) - 最常用、較安全(本文討論這個模式)
- 密碼模式 (Resource Owner Password Credentials) - 需要信任客戶端
- 客戶端憑證模式 (Client Credentials) - 應用訪問自己的資源
- 隱式模式 (Implicit) - 較不安全,已不推薦
授權(quán)模式中的術(shù)語
-
令牌 (Tokens)
- 訪問令牌 (Access Token):相當于"臨時門禁卡",用于訪問資源
- 刷新令牌 (Refresh Token):用于獲取新的訪問令牌,避免用戶頻繁重新登錄
-
......
OAuth2 協(xié)議流程解析
在看時序圖之前,必須先清楚各個角色的作用,不然就會混亂。
時序圖,簡版流程:
sequenceDiagram
actor User as 用戶
participant Client as 客戶端應用
participant AuthServer as 授權(quán)服務器
participant ResourceServer as 資源服務器
Note over User, Client: 1. 啟動授權(quán)流程
User->>Client: 訪問應用
Client->>User: 重定向到授權(quán)服務器
Note over User, AuthServer: 2. 用戶認證與授權(quán)
User->>AuthServer: 在授權(quán)頁面登錄并授權(quán)
AuthServer->>User: 重定向回應用并攜帶授權(quán)碼
Note over Client, AuthServer: 3. 交換令牌(后端通信)
Client->>AuthServer: 發(fā)送授權(quán)碼 + 客戶端憑證
AuthServer->>Client: 返回訪問令牌
Note over Client, ResourceServer: 4. 訪問資源
Client->>ResourceServer: 使用訪問令牌請求資源
ResourceServer->>Client: 返回受保護資源
Client->>User: 顯示用戶請求的內(nèi)容
更接近實際的流程,以企微授權(quán)一個工作臺應用案例為例子:
sequenceDiagram
actor 用戶
participant 客戶端 as 企業(yè)微信客戶端<br>(瀏覽器/WebView)
participant 應用 as 企微工作臺應用<br>(Your Server)
participant 授權(quán)服務器 as 企業(yè)微信<br>授權(quán)服務器
participant 資源服務器 as 企業(yè)微信<br>資源服務器
用戶->>客戶端: 1. 點擊工作臺應用圖標
客戶端->>應用: 2. 訪問應用首頁 (GET /)
Note over 應用, 授權(quán)服務器: 認證與授權(quán)階段
應用->>客戶端: 3. 重定向到企微授權(quán)頁<br>?response_type=code&redirect_uri=...
客戶端->>授權(quán)服務器: 4. 跳轉(zhuǎn)到授權(quán)頁面
授權(quán)服務器->>用戶: 5. (可選) 向用戶顯示授權(quán)同意頁面
用戶->>授權(quán)服務器: 6. 點擊同意授權(quán)
授權(quán)服務器->>客戶端: 7. 重定向到 redirect_uri 并攜帶 code
客戶端->>應用: 8. 請求 Callback URL (GET /callback?code=...)
Note over 應用, 資源服務器: 獲取訪問令牌與用戶信息
應用->>授權(quán)服務器: 9. 用 code 換取 access_token<br>(POST /token) + secret
授權(quán)服務器->>應用: 10. 返回 access_token
應用->>資源服務器: 11. 使用 access_token 獲取用戶信息<br>(GET /userinfo?access_token=...)
資源服務器->>應用: 12. 返回用戶信息 (e.g., UserId)
Note over 應用, 用戶: 正常業(yè)務訪問
應用->>應用: 13. 根據(jù)UserId處理業(yè)務邏輯<br>(e.g., 查詢數(shù)據(jù)庫)
應用->>客戶端: 14. 返回個性化應用頁面
客戶端->>用戶: 15. 顯示應用內(nèi)容
以上都是以一個用戶視角看的流程,其實后端之間還做了很多事情,才能保障整個流程的安全,不過下面的流程圖需要以一個開發(fā)者的角度看待,下面繼續(xù)解構(gòu)。
后端之間的交互流程-包含安全方案設計
下面以企業(yè)微信OAuth2授權(quán)碼流程,以開發(fā)者(應用服務器/資源服務器)的視角,看待應用如何與企微授權(quán)服務器建立聯(lián)系,包括如何獲取安全憑證(如Secret)、驗證的流程。
企業(yè)微信OAuth2授權(quán)碼流程中,開發(fā)者需要先在企微管理后臺創(chuàng)建應用,獲取應用的安全憑證(corp_id, secret等),然后在應用服務器中使用這些憑證。
整體流程分為兩個主要部分:
- 應用注冊與安全憑證發(fā)放(靜態(tài)配置)
- OAuth2授權(quán)碼流程(動態(tài)交互)
理解幾個密碼學上關(guān)鍵的工具包:
- AgentId
- Secret
- 隨機數(shù)
- 簽名-HMAC
- ......
應用注冊與安全憑證發(fā)放
這一步是確保整體安全的關(guān)鍵流程,Secret參數(shù)作為一個關(guān)鍵密鑰(可以申請更換),它也是標識身份,防抵賴性作用。
一個AgentId 對應 一把Secret密鑰。
Secret必須安全地存儲在應用服務器內(nèi),只做打簽名用。不可以暴露,否則有被冒充安全風險!
sequenceDiagram
participant 開發(fā)者
participant 企微管理后臺
participant 應用服務器
開發(fā)者->>企微管理后臺: 1. 登錄管理后臺
開發(fā)者->>企微管理后臺: 2. 創(chuàng)建應用(設置應用名稱、logo等)
企微管理后臺->>開發(fā)者: 3. 返回應用憑證:AgentId、Secret等
開發(fā)者->>應用服務器: 4. 配置AgentId和Secret
OAuth2授權(quán)碼流程
State:
客戶端生成 State 流程:
- 收集數(shù)據(jù):隨機數(shù) + 時間戳 + 會話ID + 業(yè)務參數(shù)
- 構(gòu)建結(jié)構(gòu):
- 計算簽名:HMAC-SHA256(排序后的數(shù)據(jù)字符串, client_secret)
- 添加簽名:
- Base64編碼:生成最終的state參數(shù)
客戶端/服務端驗證 State 流程:
- Base64解碼state,得到原始數(shù)據(jù)結(jié)構(gòu)
- 提取簽名值,從數(shù)據(jù)結(jié)構(gòu)中移除簽名字段
- 重新計算簽名:HMAC-SHA256(相同的排序數(shù)據(jù), client_secret)
- 對比簽名:恒定時間比較計算簽名與提取簽名
- 如果一致 → 數(shù)據(jù)未被篡改,驗證通過
- 如果不一致 → 可能被篡改,拒絕請求
graph TB
A[客戶端生成state] --> B[使用client_secret簽名]
C[客戶端驗證state] --> D[使用client_secret驗簽]
B --> E[確保數(shù)據(jù)完整性]
D --> E
再次看OAuth2授權(quán)碼流程:
流程圖是AI生成的,有些角色關(guān)系描述得不是那么準確,但是大致理解state、code的安全流程是沒問題的。請辯證的看。
sequenceDiagram
participant User as 用戶
participant Client as 客戶端應用
participant Browser as 瀏覽器
participant AuthServer as 授權(quán)服務器
participant TokenStore as 令牌存儲
Note over Client, AuthServer: State 生成與簽名階段
User->>Client: 1. 訪問應用
Client->>Client: 2. 生成 State 參數(shù)
Note right of Client: - 收集會話ID<br/>- 生成隨機數(shù)<br/>- 記錄時間戳<br/>- 添加業(yè)務上下文
Client->>Client: 3. State 簽名
Note right of Client: - 排序數(shù)據(jù)字段<br/>- 計算HMAC簽名<br/>- Base64編碼
Client->>Browser: 4. 存儲State到Session
Client->>Browser: 5. 重定向到授權(quán)頁(帶state)
Note over Browser, AuthServer: 用戶認證與授權(quán)階段
Browser->>AuthServer: 6. 請求授權(quán)頁面
AuthServer->>User: 7. 顯示登錄頁面
User->>AuthServer: 8. 輸入憑證并授權(quán)
AuthServer->>AuthServer: 9. 驗證用戶憑證
Note over AuthServer, TokenStore: Code 生成階段
AuthServer->>AuthServer: 10. 生成授權(quán)碼(Code)
Note right of AuthServer: - 關(guān)聯(lián)用戶ID<br/>- 綁定客戶端ID<br/>- 設置權(quán)限范圍<br/>- 添加時間戳
AuthServer->>TokenStore: 11. 存儲Code元數(shù)據(jù)
Note right of TokenStore: - code值<br/>- 用戶信息<br/>- 客戶端信息<br/>- 過期時間
AuthServer->>Browser: 12. 重定向回客戶端(帶code+state)
Note over Client, TokenStore: State 校驗與 Code 驗證階段
Browser->>Client: 13. 請求回調(diào)URL
Client->>Client: 14. 提取并驗證State
Note right of Client: - Base64解碼<br/>- 驗證簽名<br/>- 檢查時效性<br/>- 會話匹配
Client->>Client: 15. 清理已用State
Client->>AuthServer: 16. 用Code交換Token
AuthServer->>TokenStore: 17. 驗證Code有效性
TokenStore->>AuthServer: 18. 返回Code關(guān)聯(lián)信息
AuthServer->>AuthServer: 19. Code使用標記
AuthServer->>Client: 20. 返回訪問令牌
TokenStore->>TokenStore: 21. 清理已用Code
Client->>User: 22. 完成授權(quán)流程
為什么用code不直接返回token?
授權(quán)碼(code)的安全作用介紹:
授權(quán)碼(code)是OAuth2授權(quán)碼流程中的核心憑證,它通過前端信道傳遞(瀏覽器重定向),然后由客戶端應用在后端信道中與授權(quán)服務器交換訪問令牌。授權(quán)碼的安全作用主要包括:
- 避免訪問令牌通過前端信道傳輸,降低令牌泄露風險。
- 授權(quán)碼是短暫的,一次性使用的,降低被竊取后的風險。
- 授權(quán)碼與客戶端身份綁定,防止被其他客戶端使用。
假設,如果code被截取?
- 即使授權(quán)碼被竊取,攻擊窗口很短;
- 授權(quán)系統(tǒng)會自動清理過期的授權(quán)碼,減少存儲負擔;
雖然code也不能保證絕對安全,但是“相對安全”,防CSRF類攻擊時,它是有效的。