一、OAuth 概念
開放授權(quán)(OAuth)是一個開放標(biāo)準(zhǔn),允許用戶讓第三方應(yīng)用訪問該用戶在某一網(wǎng)站上存儲的私密的資源(如照片,視頻,聯(lián)系人列表),而無需將用戶名和密碼提供給第三方應(yīng)用。 —— 維基百科
嚴(yán)格來說,OAuth2 不是一個標(biāo)準(zhǔn)協(xié)議,而是一個安全的授權(quán)框架。其詳細(xì)描述系統(tǒng)中不同角色,用戶,服務(wù)前端應(yīng)用(如 API )以及客戶端(如網(wǎng)站或APP)之間如何實(shí)現(xiàn)相互認(rèn)證。
當(dāng)前 OAuth 協(xié)議版本是 OAuth2.0,需要注意的是,OAuth2.0 并不向下兼容 OAuth1.0。
在生活中,比較常見的 OAuth2 的使用場景是授權(quán)登錄,并且也廣泛應(yīng)用于 web、桌面應(yīng)用和移動 APP 的第三方服務(wù)提供授權(quán)登錄驗(yàn)證機(jī)制,以實(shí)現(xiàn)不同應(yīng)用直接數(shù)據(jù)訪問的權(quán)限。
二、OAuth2 重點(diǎn)名詞介紹
在 OAuth2 標(biāo)準(zhǔn)中定義了以下四種角色:
- 資源擁有者 (Resource Owner):
代表授權(quán)客戶端訪問本身資源信息的用戶(User);
- 客戶端 (Client):
代表意圖訪問受限資源的第三方應(yīng)用。
- 資源服務(wù)器 (Resource Server):
代表托管了受保護(hù)的用戶賬號信息的服務(wù)器,它與認(rèn)證服務(wù)器,可以是同一臺服務(wù)器,也可以是不同的服務(wù)器;
- 授權(quán)服務(wù)器 (Authorization Server):
代表驗(yàn)證用戶身份然后為客戶端派發(fā)資源訪問令牌的服務(wù)器,即服務(wù)提供商專門用來處理認(rèn)證的服務(wù)器;
三、OAuth2 運(yùn)行流程
1. 流程分析

(配圖來自阮一峰大佬)
大致流程概括就是:
- (A)Authrization Request
用戶打開客戶端以后,客戶端要求用戶給予授權(quán)。
- (B)Authorization Grant(Get)
用戶同意給予客戶端授權(quán)。
- (C)Authorization Grant(Post)
客戶端向授權(quán)服務(wù)器發(fā)送它自己的客戶端身份標(biāo)識和上一步中獲得的授權(quán)(authorization grant),向認(rèn)證服務(wù)器申請令牌。
- (D)Access Token(Get)
認(rèn)證服務(wù)器對客戶端進(jìn)行認(rèn)證以后,確認(rèn)無誤,同意發(fā)放令牌(access token),授權(quán)階段至此全部結(jié)束。
- (E)Access Token(Post && Validate)
客戶端使用令牌,向資源服務(wù)器申請獲取資源。
- (F)Protected Resource(Get)
資源服務(wù)器確認(rèn)令牌無誤,同意向客戶端開放資源。
理解完上面整個流程以后,我們再看看下面這張圖,能更加清晰理解 OAuth2 的整個運(yùn)行流程:

(配圖來自公眾號前端修仙之路)
從整個流程可以看出,在 B 步驟最為關(guān)鍵,即需要獲取到用戶對客戶端的授權(quán)(如我們在微信掃碼登錄時,點(diǎn)擊“確定”按鈕的步驟)。
有了這個授權(quán)以后,客戶端才能拿到令牌,進(jìn)而憑令牌向資源服務(wù)器獲取資源。
2. 案例:微信登錄
另外,微信登錄的實(shí)現(xiàn)流程也類似:

(配圖來自微信官方文檔)
其整體流程為:
第三方發(fā)起微信授權(quán)登錄請求,微信用戶允許授權(quán)第三方應(yīng)用后,微信會拉起應(yīng)用或重定向到第三方網(wǎng)站,并且?guī)鲜跈?quán)臨時票據(jù)
code參數(shù);通過
code參數(shù)加上AppID和AppSecret等,通過 API 換取access_token;通過
access_token進(jìn)行接口調(diào)用,獲取用戶基本數(shù)據(jù)資源或幫助用戶實(shí)現(xiàn)基本操作。
3. OAuth2 優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
適合快速開發(fā)實(shí)施,代碼量少,API需要被不同APP使用,且每個APP使用方式也不同的情況。
- 缺點(diǎn):
學(xué)習(xí)和理解的成本比較大,并且 OAuth2 不是一個嚴(yán)格的標(biāo)準(zhǔn)協(xié)議,在實(shí)施過程中更容易出錯。
四、OAuth2 四種授權(quán)模式
通過前面描述,可以知道OAuth 的核心就是向第三方應(yīng)用頒發(fā)令牌。
OAuth 2.0 規(guī)定了四種獲得令牌的流程。你可以選擇最適合自己的那一種,向第三方應(yīng)用頒發(fā)令牌。即以下四種授權(quán)方式:
- 授權(quán)碼(authorization-code)
- 隱藏式(implicit)
- 密碼式(password)
- 客戶端憑證(client credentials)
注意:
不管哪一種授權(quán)方式,第三方應(yīng)用申請令牌之前,都必須先到系統(tǒng)備案,說明自己的身份,然后會拿到兩個身份識別碼:客戶端 ID(client ID)和客戶端密鑰(client secret)。
這是為了防止令牌被濫用,沒有備案過的第三方應(yīng)用,是不會拿到令牌的。
1. 授權(quán)碼(authorization code)
即第三方應(yīng)用先申請一個授權(quán)碼,然后再用該碼獲取令牌。
適用于有后端的 Web 應(yīng)用,授權(quán)碼通過前端傳送,令牌則是儲存在后端,而且所有與資源服務(wù)器的通信都在后端完成。這樣的前后端分離,可以避免令牌泄漏。
這種方式也是最常用的流程,安全性最高。
整體流程

(配圖來自阮一峰大佬)
步驟分析
- 用戶從 A 網(wǎng)站跳轉(zhuǎn)到 B 網(wǎng)站,請求用戶確認(rèn)授權(quán),以獲取授權(quán)碼,其發(fā)送鏈接示意如下:
https://b.com/oauth/authorize?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read
其中:
response_type 參數(shù)表示要求返回授權(quán)碼(code);
client_id 參數(shù)讓 B 知道是誰在請求;
redirect_uri 參數(shù)是 B 接受或拒絕請求后的跳轉(zhuǎn)網(wǎng)址;
scope 參數(shù)表示要求的授權(quán)范圍(這里是只讀);
- 在 B 網(wǎng)站中,當(dāng)用戶同意授權(quán) A 網(wǎng)站,則 B 網(wǎng)站會攜帶授權(quán)碼,重定向到
redirect_uri參數(shù)指定的網(wǎng)址,就像下面這樣:
https://a.com/callback?code=AUTHORIZATION_CODE
- A 網(wǎng)站獲取授權(quán)碼以后,在 A 網(wǎng)站后端中向 B 網(wǎng)站請求令牌:
https://b.com/oauth/token?
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=CALLBACK_URL
client_id 參數(shù)和 client_secret 參數(shù)用來讓 B 確認(rèn) A 的身份( client_secret 參數(shù)是保密的,因此只能在后端發(fā)請求);
grant_type 參數(shù)的值是 AUTHORIZATION_CODE ,表示采用的授權(quán)方式是授權(quán)碼;
code 參數(shù)是上一步拿到的授權(quán)碼;
redirect_uri 參數(shù)是令牌頒發(fā)后的回調(diào)網(wǎng)址;
- B 網(wǎng)站接受請求并驗(yàn)證身份,身份驗(yàn)證通過后,會發(fā)放令牌。向
redirect_uri指定的網(wǎng)址,發(fā)送包含令牌access_token字段的JSON數(shù)據(jù),流程完畢。
2. 隱藏式(implicit)
即隱藏授權(quán)碼步驟,直接向前端發(fā)放令牌,也稱授權(quán)碼隱藏式。
整體流程

(配圖來自阮一峰大佬)
步驟分析
- 用戶從 A 網(wǎng)站跳轉(zhuǎn)到 B 網(wǎng)站,要求授權(quán)用戶數(shù)據(jù)給 A 網(wǎng)站使用。
https://b.com/oauth/authorize?
response_type=token&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read
response_type 參數(shù)為 token,表示要求直接返回令牌。
- 用戶在 B 網(wǎng)站同意授權(quán)給 A 網(wǎng)站。
當(dāng)用戶同意授權(quán)后,會跳轉(zhuǎn)到 redirect_uri 參數(shù)指定的重定向地址,并將令牌作為 URL 參數(shù)傳遞給 A 網(wǎng)站。
https://a.com/callback#token=ACCESS_TOKEN
token 參數(shù)就是令牌,A 網(wǎng)站因此直接在前端拿到令牌。
注意:
這里的令牌位置是 URL 錨點(diǎn)(即 # 號),而不是查詢字符串,這是因?yàn)殄^點(diǎn)不會發(fā)到服務(wù)器,避免泄露令牌的風(fēng)險。
適用場景:
由于直接傳遞令牌不安全,因此常常適用在對安全要求不高的場景,并且令牌有效期非常短,例如會話期間(session)有效,關(guān)閉瀏覽器便失效。
3. 密碼式(password)
即:對于信任的應(yīng)用,可以攜帶約定的用戶名和密碼進(jìn)行令牌申請。
流程分析

- A 網(wǎng)站使用 B 網(wǎng)站提供的用戶名和密碼,向 B 網(wǎng)站發(fā)起令牌請求。
https://oauth.b.com/token?
grant_type=password&
username=USERNAME&
password=PASSWORD&
client_id=CLIENT_ID
grant_type 參數(shù)是授權(quán)方式,這里的 password 表示"密碼式";
username 和 password 是 B 的用戶名和密碼。
- B 網(wǎng)站驗(yàn)證身份后直接將令牌存在 JSON 數(shù)據(jù)中,作為 HTTP 相應(yīng)返回令牌給 A 網(wǎng)站。
適用場景:
風(fēng)險較大,一般適用在對應(yīng)用高度信任的情況。
4. 客戶端憑證(client credentials)
即:給出憑證讓對方確認(rèn)并提供令牌。
流程分析
- A 應(yīng)用在命令行向 B 發(fā)出請求。
https://oauth.b.com/token?
grant_type=client_credentials&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
grant_type 參數(shù)等于 client_credentials 表示采用憑證式;
client_id 和 client_secret 用來讓 B 確認(rèn) A 的身份。
- B 網(wǎng)站驗(yàn)證身份后返回令牌。
這種方式給出的令牌,是針對第三方應(yīng)用的,而不是針對用戶的,即有可能多個用戶共享同一個令牌。
適用場景:
通過命令行請求令牌。
流程分析

五、使用令牌
當(dāng)網(wǎng)站獲取到令牌以后,接下來每個 API 請求都需要帶上令牌,其做法是在請求的頭信息中,將令牌添加 Authorization 字段中。
六、更新令牌
當(dāng)令牌有效期到了,OAuth2 允許用戶自動更新令牌,而不用讓用戶重新授權(quán)獲取新令牌。
具體流程:
在 B 網(wǎng)站發(fā)放令牌時,一次性發(fā)放 2 個令牌,一個用于獲取數(shù)據(jù),一個用于獲取新的令牌(refresh token 字段)。令牌到期后,用戶使用 refresh token 發(fā)送請求去更新令牌:
https://b.com/oauth/token?
grant_type=refresh_token&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
refresh_token=REFRESH_TOKEN
grant_type 參數(shù)為 refresh_token 表示要求更新令牌;
client_id 參數(shù)和 client_secret 參數(shù)用于確認(rèn)身份;
refresh_token 參數(shù)就是用于更新令牌的令牌。
B 網(wǎng)站驗(yàn)證通過以后,就會頒發(fā)新的令牌。
參考文章
- 部門內(nèi)部培訓(xùn)資料
- 《OAuth 2 深入介紹》
- 《阮一峰 理解OAuth 2.0》
- 《阮一峰 OAuth 2.0 的四種方式》
關(guān)于我
本文首發(fā)在 pingan8787個人博客,如需轉(zhuǎn)載請聯(lián)系本人。
| Author | 王平安 |
|---|---|
| pingan8787@qq.com | |
| 博 客 | www.pingan8787.com |
| 微 信 | pingan8787 |
| 每日文章推薦 | https://github.com/pingan8787/Leo_Reading/issues |
| ES小冊 | js.pingan8787.com |
微信公眾號
