https://deepzz.com/post/what-is-oauth2-protocol.html
Desc:什么是oauth2協(xié)議,oauth2應(yīng)用在哪些場景混蔼,oauth2如何實(shí)現(xiàn)單點(diǎn)登錄
什么是 OAuth 2.0
OAuth 2.0 是一個(gè)行業(yè)的標(biāo)準(zhǔn)授權(quán)協(xié)議履腋。OAuth 2.0 專注于簡化客戶端開發(fā)人員,同時(shí)為 Web 應(yīng)用程序惭嚣,桌面應(yīng)用程序遵湖,手機(jī)和客廳設(shè)備提供特定的授權(quán)流程。
它的最終目的是為第三方應(yīng)用頒發(fā)一個(gè)有時(shí)效性的令牌 token晚吞。使得第三方應(yīng)用能夠通過該令牌獲取相關(guān)的資源延旧。常見的場景就是:第三方登錄。當(dāng)你想要登錄某個(gè)論壇槽地,但沒有賬號(hào)迁沫,而這個(gè)論壇接入了如 QQ芦瘾、Facebook 等登錄功能,在你使用 QQ 登錄的過程中就使用的 OAuth 2.0 協(xié)議集畅。
如果你想了解更多近弟,其官方網(wǎng)址為:https://oauth.net/2/。下面我們來了解下 OAuth 協(xié)議的基本原理
角色
首先需要介紹的是 OAuth 2.0 協(xié)議中的一些角色挺智,整個(gè)授權(quán)協(xié)議的流程都將圍繞著這些角色:
-
resource owner
祷愉,資源所有者,能夠允許訪問受保護(hù)資源的實(shí)體赦颇。如果是個(gè)人二鳄,被稱為 end-user。 -
resource server
媒怯,資源服務(wù)器订讼,托管受保護(hù)資源的服務(wù)器。 -
client
沪摄,客戶端躯嫉,使用資源所有者的授權(quán)代表資源所有者發(fā)起對受保護(hù)資源的請求的應(yīng)用程序。如:web網(wǎng)站杨拐,移動(dòng)應(yīng)用等祈餐。 -
authorization server
,授權(quán)服務(wù)器哄陶,能夠向客戶端頒發(fā)令牌帆阳。 -
user-agent
,用戶代理屋吨,幫助資源所有者與客戶端溝通的工具蜒谤,一般為 web 瀏覽器,移動(dòng) APP
等至扰。
可能有些朋友依然不太理解鳍徽,這里舉例說明:假如我想要在 coding.net
這個(gè)網(wǎng)站上用 github.com
的賬號(hào)登錄。那么 coding 相對于 github 就是一個(gè)客戶端敢课。而我們用什么操作的呢阶祭?瀏覽器,這就是一個(gè)用戶代理直秆。當(dāng)從 github 的授權(quán)服務(wù)器獲得 token 后濒募,coding 是需要請求 github 賬號(hào)信息的,從哪請求圾结?從 github 的資源服務(wù)器瑰剃。
協(xié)議流程
上圖詳細(xì)的描述了這四個(gè)角色之間的步驟流程:
- (A) Client 請求 Resource Owner 的授權(quán)。授權(quán)請求可以直接向 Resource Owner 請求筝野,也可以通過 Authorization Server 間接的進(jìn)行晌姚。
- (B) Client 獲得授權(quán)許可粤剧。
- (C) Client 向 Authorization Server 請求訪問令牌。
- (D) Authorization Server 驗(yàn)證授權(quán)許可挥唠,如果有效則頒發(fā)訪問令牌俊扳。
- (E) Client 通過訪問令牌從 Resource Server 請求受保護(hù)資源。
- (F) Resource Server 驗(yàn)證訪問令牌猛遍,有效則響應(yīng)請求。
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
Figure 1: Abstract Protocol Flow
授權(quán)
一個(gè)客戶端想要獲得授權(quán)号坡,就需要先到服務(wù)商那注冊你的應(yīng)用懊烤。一般需要你提供下面這些信息:
- 應(yīng)用名稱
- 應(yīng)用網(wǎng)站
- 重定向 URI 或回調(diào) URL(redirect_uri)
重定向 URI 是服務(wù)商在用戶授權(quán)(或拒絕)應(yīng)用程序之后重定向用戶的地址,因此也是用于處理授權(quán)代碼或訪問令牌的應(yīng)用程序的一部分宽堆。在你注冊成功之后腌紧,你會(huì)從服務(wù)商那獲取到你的應(yīng)用相關(guān)的信息:
- 客戶端標(biāo)識(shí) client_id
- 客戶端密鑰 client_secret
client_id
用來表識(shí)客戶端(公開),client_secret
用來驗(yàn)證客戶端身份(保密)畜隶。
授權(quán)類型
OAuth 2.0 列舉了四種授權(quán)類型壁肋,分別用于不同的場景:
- Authorization Code(授權(quán)碼 code):服務(wù)器與客戶端配合使用。
- Implicit(隱式 token):用于移動(dòng)應(yīng)用程序或 Web 應(yīng)用程序(在用戶設(shè)備上運(yùn)行的應(yīng)用程序)籽慢。
- Resource Owner Password Credentials(資源所有者密碼憑證 password):資源所有者和客戶端之間具有高度信任時(shí)(例如浸遗,客戶端是設(shè)備的操作系統(tǒng)的一部分,或者是一個(gè)高度特權(quán)應(yīng)用程序)箱亿,以及當(dāng)其他授權(quán)許可類型(例如授權(quán)碼)不可用時(shí)被使用跛锌。
- Client Credentials(客戶端證書 client_credentials):當(dāng)客戶端代表自己表演(客戶端也是資源所有者)或者基于與授權(quán)服務(wù)器事先商定的授權(quán)請求對受保護(hù)資源的訪問權(quán)限時(shí),客戶端憑據(jù)被用作為授權(quán)許可届惋。
下面來具體說說這四種授權(quán)髓帽。注意重定向一定要用 302。
授權(quán)碼模式
該方式需要資源服務(wù)器的參與脑豹,應(yīng)用場景大概是:
- 資源擁有者(用戶)需要登錄客戶端(APP)郑藏,他選擇了第三方登錄。
- 客戶端(APP)重定向到第三方授權(quán)服務(wù)器瘩欺。此時(shí)客戶端攜帶了客戶端標(biāo)識(shí)(client_id)必盖,那么第三方就知道這是哪個(gè)客戶端,資源擁有者確定(拒絕)授權(quán)后需要重定向到哪里击碗。
- 用戶確認(rèn)授權(quán)筑悴,客戶端(APP)被重定向到注冊時(shí)給定的 URI,并攜帶了第三方給定的 code稍途。
- 在重定向的過程中阁吝,客戶端拿到 code 與
client_id
、client_secret
去授權(quán)服務(wù)器請求令牌械拍,如果成功突勇,直接請求資源服務(wù)器獲取資源装盯,整個(gè)過程,用戶代理是不會(huì)拿到令牌 token 的甲馋。 - 客戶端(APP)拿到令牌 token 后就可以向第三方的資源服務(wù)器請求資源了埂奈。
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI ---->| |
| User- | | Authorization |
| Agent -+----(B)-- User authenticates --->| Server |
| | | |
| -+----(C)-- Authorization Code ---<| |
+-|----|---+ +---------------+
| | ^ v
(A) (C) | |
| | | |
^ v | |
+---------+ | |
| |>---(D)-- Authorization Code ---------' |
| Client | & Redirection URI |
| | |
| |<---(E)----- Access Token -------------------'
+---------+ (w/ Optional Refresh Token)
Note: The lines illustrating steps (A), (B), and (C) are broken into
two parts as they pass through the user-agent.
Figure 3: Authorization Code Flow
具體說明,這里以 coding 和 github 為例定躏。當(dāng)我想在 coding 上通過 github 賬號(hào)登錄時(shí):
1账磺、GET 請求
點(diǎn)擊登錄,重定向到 github 的授權(quán)端點(diǎn):
https://github.com/login/oauth/authorize?
response_type=code&
client_id=a5ce5a6c7e8c39567ca0&
redirect_uri=https://coding.net/api/oauth/github/callback&
scope=user:email
字段 | 描述 |
---|---|
response_type | 必須痊远,固定為 code垮抗,表示這是一個(gè)授權(quán)碼請求。 |
client_id | 必須碧聪,在 github 注冊獲得的客戶端 ID冒版。 |
redirect_uri | 可選,通過客戶端注冊的重定向 URI(一般要求且與注冊時(shí)一致)逞姿。 |
scope | 可選辞嗡,請求資源范圍,多個(gè)用逗號(hào)隔開滞造。 |
state | 可選(推薦)续室,如果存在,原樣返回給客戶端谒养。 |
返回值:
https://coding.net/api/oauth/github/callback?code=fb6a88dc09e843b33f
字段 | 描述 |
---|---|
code | 必須猎贴。授權(quán)碼 |
state | 如果出現(xiàn)在請求中,必須包含蝴光。 |
授權(quán)錯(cuò)誤
第一種她渴,客戶端沒有被識(shí)別或錯(cuò)誤的重定向 URI,授權(quán)服務(wù)器沒有必要重定向資源擁有者到重定向URI蔑祟,而是通知資源擁有者發(fā)生了錯(cuò)誤趁耗。
第二種,客戶端被正確地授權(quán)了疆虚,但是其他某些事情失敗了苛败。這種情況下下面地錯(cuò)誤響應(yīng)會(huì)被發(fā)送到客戶端,包括在重定向 URI 中径簿。
https://coding.net/api/oauth/github/callback?
error=redirect_uri_mismatch&
error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&
error_uri=https%3A%2F%2Fdeveloper.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch
字段 | 描述 |
---|---|
error | 必須罢屈,必須是預(yù)先定義的錯(cuò)誤碼。 |
error_description | 可選篇亭,錯(cuò)誤描述 |
error_uri | 可選缠捌,指向可解讀錯(cuò)誤的 URI |
state | 必須,如果出現(xiàn)在授權(quán)請求中 |
2译蒂、POST 請求
獲取令牌 token曼月,當(dāng)獲取到授權(quán)碼 code 后谊却,客戶端需要用它獲取訪問令牌:
https://github.com/login/oauth/access_token?
client_id=a5ce5a6c7e8c39567ca0&
client_secret=xxxx&
grant_type=authorization_code&
code=fb6a88dc09e843b33f&
redirect_uri=https://coding.net/api/oauth/github/callback
字段 | 描述 |
---|---|
client_id | 必須,客戶端標(biāo)識(shí)哑芹。 |
client_secret | 必須炎辨,客戶端密鑰。 |
grant_type | 必須聪姿,固定為 authorization_code/refresh_token碴萧。 |
code | 必須,上一步獲取到的授權(quán)碼末购。 |
redirect_uri | 必須勿决,完成授權(quán)后的回調(diào)地址,與注冊時(shí)一致招盲。 |
返回值:
{
"access_token":"a14afef0f66fcffce3e0fcd2e34f6ff4",
"token_type":"bearer",
"expires_in":3920,
"refresh_token":"5d633d136b6d56a41829b73a424803ec"
}
字段 | 描述 |
---|---|
access_token | 這個(gè)就是最終獲取到的令牌。 |
token_type | 令牌類型嘉冒,常見有 bearer/mac/token(可自定義)曹货。 |
expires_in | 失效時(shí)間。 |
refresh_token | 刷新令牌讳推,用來刷新 access_token顶籽。 |
3、獲取資源服務(wù)器資源银觅,拿著 access_token 就可以獲取賬號(hào)的相關(guān)信息了:
curl -H "Authorization: token a14afef0f66fcffce3e0fcd2e34f6ff4" https://api.github.com/user
4礼饱、POST 請求
刷新令牌
我們的 access_token 是有時(shí)效性的,當(dāng)在獲取 github 用戶信息時(shí)究驴,如果返回 token 過期:
https://github.com/login/oauth/access_token?
client_id=a5ce5a6c7e8c39567ca0&
client_secret=xxxx&
redirect_uri=https://coding.net/api/oauth/github/callback&
grant_type=refresh_token&
refresh_token=5d633d136b6d56a41829b73a424803ec
字段 | 描述 |
---|---|
client_id | 必須 |
client_secret | 必須 |
redirect_uri | 必須 |
grant_type | 必須镊绪,固定為 refresh_token |
refresh_token | 必須,上面獲取到的 refresh_token |
返回值:
{
"access_token":"a14afef0f66fcffce3e0fcd2e34f6ee4",
"token_type":"bearer",
"expires_in":3920,
"refresh_token":"4a633d136b6d56a41829b73a424803vd"
}
refresh_token 只有在 access_token 過期時(shí)才能使用洒忧,并且只能使用一次蝴韭。當(dāng)換取到的 access_token 再次過期時(shí),使用新的 refresh_token 來換取 access_token
+--------+ +---------------+
| |--(A)------- Authorization Grant --------->| |
| | | |
| |<-(B)----------- Access Token -------------| |
| | & Refresh Token | |
| | | |
| | +----------+ | |
| |--(C)---- Access Token ---->| | | |
| | | | | |
| |<-(D)- Protected Resource --| Resource | | Authorization |
| Client | | Server | | Server |
| |--(E)---- Access Token ---->| | | |
| | | | | |
| |<-(F)- Invalid Token Error -| | | |
| | +----------+ | |
| | | |
| |--(G)----------- Refresh Token ----------->| |
| | | |
| |<-(H)----------- Access Token -------------| |
+--------+ & Optional Refresh Token +---------------+
Figure 2: Refreshing an Expired Access Token
隱式模式
該方式一般用于移動(dòng)客戶端或網(wǎng)頁客戶端熙侍。隱式授權(quán)類似于授權(quán)碼授權(quán)榄鉴,但 token 被返回給用戶代理再轉(zhuǎn)發(fā)到客戶端(APP),因此它可能會(huì)暴露給用戶和用戶設(shè)備上的其它客戶端(APP)蛉抓。此外庆尘,此流程不會(huì)對客戶端(APP)的身份進(jìn)行身份驗(yàn)證,并且依賴重定向 URI(已在服務(wù)商中注冊)來實(shí)現(xiàn)此目的巷送。
基本原理:要求用戶授權(quán)應(yīng)用程序驶忌,然后授權(quán)服務(wù)器將訪問令牌傳回給用戶代理,用戶代理將其傳遞給客戶端笑跛。
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI --->| |
| User- | | Authorization |
| Agent -|----(B)-- User authenticates -->| Server |
| | | |
| |<---(C)--- Redirection URI ----<| |
| | with Access Token +---------------+
| | in Fragment
| | +---------------+
| |----(D)--- Redirection URI ---->| Web-Hosted |
| | without Fragment | Client |
| | | Resource |
| (F) |<---(E)------- Script ---------<| |
| | +---------------+
+-|--------+
| |
(A) (G) Access Token
| |
^ v
+---------+
| |
| Client |
| |
+---------+
Note: The lines illustrating steps (A) and (B) are broken into two
parts as they pass through the user-agent.
Figure 4: Implicit Grant Flow
1位岔、同樣以 coding 和 github 為例:
https://github.com/login/oauth/authorize?
response_type=token&
client_id=a5ce5a6c7e8c39567ca0&
redirect_uri=https://coding.net/api/oauth/github/callback&
scope=user:email
字段 | 描述 |
---|---|
response_type | 必須如筛,固定為 token。 |
client_id | 必須抒抬。當(dāng)客戶端被注冊時(shí)杨刨,有授權(quán)服務(wù)器分配的客戶端標(biāo)識(shí)。 |
redirect_uri | 可選擦剑。由客戶端注冊的重定向URI妖胀。 |
scope | 可選。請求可能的作用域惠勒。 |
state | 可選(推薦)赚抡。任何需要被傳遞到客戶端請求的URI客戶端的狀態(tài)。 |
返回值:
https://coding.net/api/oauth/github/callback#
access_token=a14afef0f66fcffce3e0fcd2e34f6ff4&
token_type=token&
expires_in=3600
字段 | 描述 |
---|---|
access_token | 必須纠屋。授權(quán)服務(wù)器分配的訪問令牌涂臣。 |
token_type | 必須。令牌類型售担。 |
expires_in | 推薦赁遗,訪問令牌過期的秒數(shù)。 |
scope | 可選族铆,訪問令牌的作用域岩四。 |
state | 必須,如果出現(xiàn)在授權(quán)請求期間哥攘,和請求中的 state 參數(shù)一樣剖煌。 |
授權(quán)錯(cuò)誤和上面一樣
2、用戶代理提取令牌 token 并提交給 coding
3逝淹、coding 拿到 token 就可以獲取用戶信息了
curl -H "Authorization: token a14afef0f66fcffce3e0fcd2e34f6ff4" https://api.github.com/user
資源所有者密碼模式
用戶將其服務(wù)憑證(用戶名和密碼)直接提供給客戶端耕姊,該客戶端使用憑據(jù)從服務(wù)獲取訪問令牌。如果其它方式不可行栅葡,則只應(yīng)在授權(quán)服務(wù)器上啟用該授權(quán)類型箩做。此外,只有在客戶端受到用戶信任時(shí)才能使用它(例如妥畏,它由服務(wù)商自有邦邦,或用戶的桌面操作系統(tǒng))。
+----------+
| Resource |
| Owner |
| |
+----------+
v
| Resource Owner
(A) Password Credentials
|
v
+---------+ +---------------+
| |>--(B)---- Resource Owner ------->| |
| | Password Credentials | Authorization |
| Client | | Server |
| |<--(C)---- Access Token ---------<| |
| | (w/ Optional Refresh Token) | |
+---------+ +---------------+
Figure 5: Resource Owner Password Credentials Flow
POST 請求
密碼憑證流程
https://oauth.example.com/token?grant_type=password&username=USERNAME&password=PASSWORD&client_id=CLIENT_ID
字段 | 描述 |
---|---|
grant_type | 必須醉蚁,固定為 password燃辖。 |
username | 必須,UTF-8 編碼的資源擁有者用戶名网棍。 |
password | 必須黔龟,UTF-8 編碼的資源擁有者密碼。 |
scope | 可選,授權(quán)范圍氏身。 |
返回值:
{
"access_token" : "...",
"token_type" : "...",
"expires_in" : "...",
"refresh_token" : "...",
}
如果授權(quán)服務(wù)器驗(yàn)證成功巍棱,那么將直接返回令牌 token,改客戶端已被授權(quán)蛋欣。
客戶端模式
這種模式只需要提供 client_id
和 client_secret
即可獲取授權(quán)航徙。一般用于后端 API 的相關(guān)操作。
+---------+ +---------------+
| | | |
| |>--(A)- Client Authentication --->| Authorization |
| Client | | Server |
| |<--(B)---- Access Token ---------<| |
| | | |
+---------+ +---------------+
Figure 6: Client Credentials Flow
POST 請求
客戶端憑證流程:
https://oauth.example.com/token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
字段 | 描述 |
---|---|
grant_type | 必須陷虎。必須設(shè)置到客戶端證書中到踏。 |
scope | 可選。授權(quán)的作用域尚猿。 |
返回值
{
"access_token" : "...",
"token_type" : "...",
"expires_in" : "...",
}
如果授權(quán)服務(wù)器驗(yàn)證成功窝稿,那么將直接返回令牌 token,改客戶端已被授權(quán)凿掂。
參考網(wǎng)站
[1] https://developers.douban.com/wiki/?title=oauth2
[2] https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2