背景
我們先從一個(gè)非常典型例子出發(fā)蚕泽,假如你在某網(wǎng)盤(pán)上傳了你的很多圖片晌梨,網(wǎng)盤(pán)提供了圖片存儲(chǔ),另一個(gè)某打印店提供了在線打印圖片须妻。
由于存儲(chǔ)和答應(yīng)是由兩家不同的服務(wù)商提供的仔蝌,兩家各自都提供了用戶的注冊(cè)功能,所以如果你要想在打印店上去打印你放在網(wǎng)盤(pán)的照片時(shí)荒吏,此時(shí)你會(huì)想到2種方案:
- 假設(shè)你的賬戶密碼都不一樣敛惊,你可以先將待打印的圖片從網(wǎng)盤(pán)上下載下來(lái),然后在上傳到打印店的網(wǎng)站上绰更,之后進(jìn)行打印瞧挤。這種模式是最原始,也是效率最低下儡湾。
- 為了省事皿伺,你可以將你網(wǎng)盤(pán)的賬戶密碼交給打印店老板,告訴他你要打印的圖片盒粮,讓他給你操作鸵鸥,省事,但是風(fēng)險(xiǎn)太大,帳號(hào)密碼都泄漏了妒穴,就不怕別人去篡改個(gè)人信息或者查看你的隱私宋税?
之前很多公司包括Google
、Yahoo
讼油、Microsoft
都嘗試解決這個(gè)問(wèn)題杰赛,這也促使OAuth
的誕生。
什么是 OAuth 矮台?
OAuth(Open Authorization
)是一個(gè)開(kāi)放標(biāo)準(zhǔn)乏屯,允許用戶讓第三方應(yīng)用訪問(wèn)該用戶在某一網(wǎng)站上存儲(chǔ)的私密的資源(如照片,視頻瘦赫,聯(lián)系人列表)辰晕,而不需要將用戶名和密碼提供給第三方網(wǎng)站或分享他們數(shù)據(jù)的所有內(nèi)容,目前在全世界范圍內(nèi)得到廣泛應(yīng)用确虱。
OAuth 解決思路
OAuth
在 客戶端(Client
) 即 打印店 與 資源服務(wù)器(Resource Server
) 即 網(wǎng)盤(pán) 之間含友,設(shè)置了一個(gè)授權(quán)層(Authorization Layer
),通過(guò) 授權(quán)服務(wù)器(Authorization Server
) 提供用戶授權(quán)校辩。
客戶端 要想訪問(wèn) 資源服務(wù)器 必須要經(jīng)過(guò) 授權(quán)層窘问,用戶 即 資源擁有者(Resource Owner
) 可以在登錄的時(shí)候,指定授權(quán)層令牌的權(quán)限范圍和有效期宜咒,當(dāng)用戶同意授權(quán)后才向客戶端開(kāi)放用戶儲(chǔ)存的資料惠赫。
通俗來(lái)說(shuō):當(dāng)打印店要訪問(wèn)用戶的你網(wǎng)盤(pán)的圖片時(shí),通過(guò)OAuth
機(jī)制故黑,打印店要向網(wǎng)盤(pán)的授權(quán)服務(wù)器請(qǐng)求授權(quán)汉形,網(wǎng)盤(pán)服務(wù)商將引導(dǎo)你在網(wǎng)盤(pán)的網(wǎng)站上登錄,并詢問(wèn)你是否將訪問(wèn)圖片的服務(wù)授權(quán)給打印店倍阐。當(dāng)你點(diǎn)擊同意后,打印店就可以訪問(wèn)你網(wǎng)盤(pán)上的圖片服務(wù)逗威。整個(gè)過(guò)程打印店沒(méi)有觸及到你網(wǎng)盤(pán)的帳號(hào)信息峰搪,安全便捷。
OAuth 授權(quán)流程
+--------+ +---------------+
| |--(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 ---| |
+--------+ +---------------+
大體流程如下:
-
Authrization Request
:用戶打開(kāi)客戶端凯旭,客戶端向用戶請(qǐng)求對(duì)資源服務(wù)器的authorization grant
概耻,要求用戶給予授權(quán)。 -
Authorization Grant(Get)
:用戶同意授權(quán)請(qǐng)求罐呼,客戶端將收到一個(gè)authorization grant
授權(quán)許可鞠柄。 -
Authorization Grant(Post)
:客戶端向授權(quán)服務(wù)器發(fā)送它自己的客戶端身份標(biāo)識(shí)和上一步中的authorization grant
授權(quán)許可,請(qǐng)求訪問(wèn)令牌嫉柴。 -
Access Token(Get)
:認(rèn)證服務(wù)器對(duì)客戶端身份進(jìn)行認(rèn)證厌杜,如果認(rèn)證通過(guò)并且authorization grant
也被驗(yàn)證通過(guò),授權(quán)服務(wù)器將為客戶端派發(fā)access token
訪問(wèn)令牌,授權(quán)階段至此全部結(jié)束夯尽。 -
Access Token(Post && Validate)
:客戶端向資源服務(wù)器發(fā)送access token
用于驗(yàn)證并請(qǐng)求資源信息瞧壮。 -
Protected Resource(Get)
:資源服務(wù)器進(jìn)行請(qǐng)求驗(yàn)證,如果access token
驗(yàn)證通過(guò)匙握,資源服務(wù)器將向客戶端返回資源信息咆槽。
授權(quán)模式
根據(jù)應(yīng)用請(qǐng)求授權(quán)的方式和授權(quán)方服務(wù)支持的 Grant Type
的不同,OAuth 2
定義了四種 Grant Type
(授權(quán)模式)圈纺,每一種都有適用的應(yīng)用場(chǎng)景:
- 授權(quán)碼模式(
Authorization Code
):最常使用的一種授權(quán)許可類(lèi)型秦忿,結(jié)合普通服務(wù)器端應(yīng)用使用。 - 隱式授權(quán)模式(
Implicit
):跳過(guò)授權(quán)碼這個(gè)步驟蛾娶,適用于移動(dòng)應(yīng)用或Web App
- 密碼模式(
Resource Owner Password Credentials
):客戶端提供帳號(hào)密碼灯谣,向服務(wù)商索要授權(quán),適用于受信任客戶端應(yīng)用 - 客戶端模式(
Client Credentials
):客戶端直接向服務(wù)商索取授權(quán)茫叭,適用于客戶端調(diào)用主服務(wù)API
型應(yīng)用
授權(quán)碼模式(Authorization Code
)
是目前互聯(lián)網(wǎng)上最常使用的一種授權(quán)模式酬屉,比如QQ
,微博揍愁,Facebook
和豆瓣等等呐萨,它要求第三方應(yīng)用先申請(qǐng)一個(gè)授權(quán)碼(Authorization Code
),然后再用該碼獲取令牌莽囤,請(qǐng)求數(shù)據(jù)谬擦,流程如下:
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ +---------------+
| -+----(A)-- User Authorization Request ---->| |
| User- | | Authorization |
| Agent -+----(B)-- User authenticates ------------>| Server |
| | | |
| -+----(C)-- Authorization Code Grant ------<| |
+-|----|---+ +---------------+
| | ^ v
(A) (C) | |
| | | |
^ v | |
+---------+ | |
| |>---(D)-- Access Token Request ---------------' |
| Client | |
| | |
| |< ---(E)-- Access Token Grant -----------------------'
+---------+ (w/ Optional Refresh Token)
User Authorization Request
:用戶訪問(wèn)客戶端,客戶端構(gòu)造了一個(gè)用于請(qǐng)求authorization code
的URL
并引導(dǎo)用戶跳轉(zhuǎn)訪問(wèn)朽缎,鏈接格式大概如下:
https://open.server-name.com/oauth2/authorize
?response_type=code
&client_id=AppID
&redirect_uri=REDIRECT_URI
&scope=SCOPE
&state=STATE
-
response_type
:授權(quán)模式惨远,必選,此時(shí)值固定為code
-
client_id
:客戶端身份標(biāo)識(shí)话肖,一般是注冊(cè)時(shí)候的分配的AppID
-
redirect_uri
:授權(quán)成功后重定向地址北秽,必選,注意需要將uri
進(jìn)行URLEncode
-
scope
:授權(quán)范圍最筒,可選 -
state
:客戶端的狀態(tài)值贺氓,必選,一般是隨機(jī)字符串床蜘,成功授權(quán)后回調(diào)時(shí)會(huì)原樣帶回辙培,為了防止CSRF
攻擊
User authenticates
:用戶決定是否給客戶端授權(quán),授權(quán)服務(wù)會(huì)提示用戶授權(quán)或拒絕應(yīng)用程序訪問(wèn)其帳戶信息
Authorization Code Grant
:用戶確認(rèn)授權(quán)邢锯,授權(quán)服務(wù)器將重定向之前客戶端提供的redirect_uri
地址扬蕊,并附帶code
和state
參數(shù),客戶端便能取到authorization code
的值丹擎,鏈接格式大概如下:
https://client-name.com/redirect_url
?code=520DD95263C1CFEA087
&state=STATE
-
code
:授權(quán)服務(wù)器生成的authorization code
尾抑,即授權(quán)碼,code
有效期較短,一般維持在5 - 10
分鐘蛮穿,授權(quán)服務(wù)器可自行配置 -
state
:即客戶端之前攜帶的state
值庶骄,可進(jìn)行檢查對(duì)比與最初設(shè)置的狀態(tài)值相匹配,防止CSRF
攻擊
Access Token Request
:客戶端獲取到授權(quán)碼 code
后践磅,可向服務(wù)器請(qǐng)求(post
)獲取 access_token
单刁,一般來(lái)說(shuō)請(qǐng)求參數(shù)如下:
參數(shù) | 是否必須 | 含義 |
---|---|---|
grant_type | 必須 | 授權(quán)類(lèi)型,此值固定為authorization_code
|
code | 必須 | 授權(quán)碼 |
client_id | 必須 | 客戶端標(biāo)識(shí)府适,一般是第三方分配的AppID
|
client_secret | 必須 | 客戶端密鑰羔飞,一般是第三方分配的AppSecret
|
redirect_uri | 必須 | 回調(diào)地址,與之前的 redirect_uri 保持一致 |
Access Token Grant
:服務(wù)器會(huì)驗(yàn)證客戶端傳過(guò)來(lái)的參數(shù)檐春,驗(yàn)證通過(guò)后逻淌,給客戶端返回 access token
,一般返回?cái)?shù)據(jù)格式如下:
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example"疟暖,
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"scope":"user_info"
}
-
access_token
:訪問(wèn)令牌 -
token_type
:令牌類(lèi)型 -
expires_in
:令牌過(guò)期時(shí)間 -
refresh_token
:刷新令牌 -
scope
:權(quán)限范圍
其中 refresh_token
用于在授權(quán)自動(dòng)續(xù)期步驟中卡儒,獲取新的Access_Token
時(shí)需要提供的參數(shù)。
至此俐巴,授權(quán)流程全部結(jié)束骨望。
隱式授權(quán)模式(Implicit
)
跟前面的Authorization Code
模式非常相似,只是省略掉了頒發(fā)授權(quán)碼(Authorization Code)
給客戶端的過(guò)程欣舵,而是直接返回訪問(wèn)令牌和可選的刷新令牌擎鸠。適用于沒(méi)有Server
服務(wù)器來(lái)接受處理Authorization Code
的第三方應(yīng)用,其整個(gè)流程如下:
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ +---------------+
| -+----(A)-- User Authorization Request --->| |
| User- | | Authorization |
| Agent -|----(B)-- User Authenticates ----------->| Server |
| | | |
| |<---(C)-- Redirect URI With ------------<| |
| | Access Token +---------------+
| |
| | +---------------+
| |----(D)---Follow Redirect URI --------->| Web-Hosted |
| | | Client |
| | | Resource |
| |<---(E)-- Send Token Extract Script ----<| |
| | +---------------+
+-|--------+
| |
(A) (F) Pass Token to Application
| |
^ v
+---------+
| |
| Client |
| |
User Authorization Request
:客戶端提構(gòu)造了一個(gè)用于請(qǐng)求授權(quán)的鏈接缘圈,鏈接格式大概如下:
https://open.server-name.com/oauth2/authorize
?response_type=token
&client_id=AppID
&redirect_uri=REDIRECT_URI
&scope=SCOPE
&state=STATE
與之前的授權(quán)碼模式相比劣光,只是將 response_type
換成了 token
User Authenticates
:與之前的相同,用戶決定是否給客戶端授權(quán)
Redirect URI With Access Token
:用戶同意授權(quán)糟把,認(rèn)證服務(wù)器將用戶重定向到客戶端指定的重定向redirect_uri
绢涡,并在uri
的中添加訪問(wèn)令牌,鏈接格式大概如下:
http://client.name.com/redirect_url/#access_token=2YotnFZFEjr1zCsicMWpAA&token_type=Bearer&expires_in=3600&scope=SCOPE&state=STATE
此時(shí)的 token_type
恒為 Bearer
遣疯。
要注意的是雄可,返回值放到了REDIRECT_URI
的 hash
部分,而不是作為 ?query
參數(shù)另锋,這樣瀏覽器在訪問(wèn)重定向指定的url
時(shí),就不會(huì)把這些數(shù)據(jù)發(fā)送到服務(wù)器狭归。
Follow Redirect URI
:瀏覽器請(qǐng)求redirect_uri
標(biāo)識(shí)的客戶端地址夭坪,此時(shí)不包含hash
值,并保留access_token
相關(guān)信息过椎。
Send Token Extract Script
:客戶端返回一個(gè)包含 token
的頁(yè)面室梅,頁(yè)面執(zhí)行腳本獲取 redirect_uri
中的 access_token
。
Pass Token to Application
:瀏覽器獲取的令牌發(fā)給客戶端。
至此亡鼠,授權(quán)流程全部結(jié)束赏殃。
密碼模式(Resource Owner Password Credentials
)
這種模式更加簡(jiǎn)化,客戶端直接使用用戶提供的username
和password
來(lái)直接請(qǐng)求獲取access_token
信息间涵,這種模式一般適用于用戶高度信任第三方客戶端的情況仁热,其整個(gè)流程如下:
+----------+
| Resource |
| Owner |
| |
+----------+
v
|
(A) Resource Owner Password Credentials From User Input
|
v
+---------+ +---------------+
| |>--(B)---- Resource Owner ----------------->| |
| | Password Credentials To Server | Authorization |
| Client | | Server |
| |<--(C)- Access Token Passed To Application-<| |
| | (w/ Optional Refresh Token) | |
+---------+ +---------------+
Resource Owner Password Credentials From User Input
:用戶向客戶端提供用戶名與密碼作為授權(quán)憑據(jù)。
Resource Owner Password Credentials From Client To Server
:客戶端向授權(quán)服務(wù)器發(fā)送用戶輸入的授權(quán)憑據(jù)以請(qǐng)求 access token
(要求客戶端必須已經(jīng)在服務(wù)器端進(jìn)行注冊(cè))勾哩,其請(qǐng)求參數(shù)主要如下:
參數(shù) | 是否必須 | 含義 |
---|---|---|
grant_type | 必須 | 授權(quán)類(lèi)型抗蠢,此值固定為password
|
username | 必須 | 用戶登陸名 |
passward | 必須 | 用戶登陸密碼 |
scope | 非必須 | 授權(quán)范圍 |
Access Token Passed To Application
:授權(quán)服務(wù)器對(duì)客戶端進(jìn)行認(rèn)證并檢驗(yàn)用戶憑據(jù)的合法性,如果檢驗(yàn)通過(guò)思劳,將向客戶端返回 access token
迅矛。
至此,授權(quán)流程結(jié)束潜叛。
客戶端模式(Client Credentials
)
這是最簡(jiǎn)單的一種授權(quán)模式秽褒,客戶端直接已自己的名義,而不是用戶的名義直接去授權(quán)服務(wù)器發(fā)起授權(quán)威兜,獲取 access_token
销斟,流程也是非常簡(jiǎn)單:
+---------+ +---------------+
| | | |
| |>--(A)- Client Authentication --->| Authorization |
| Client | | Server |
| |<--(B)---- Access Token ---------<| |
| | | |
+---------+ +---------------+
Client Authentication
:客戶端直接發(fā)起授權(quán)請(qǐng)求,此時(shí)的 grant_type
的值為 client_credentials
Access Token
:認(rèn)證服務(wù)器確認(rèn)身份后牡属,向客戶端發(fā)放 access_token
小試牛刀
鑒于授權(quán)碼模式(Authorization Code
) 是目前來(lái)說(shuō)使用最為廣泛票堵,流程也時(shí)最為最完整、流程最嚴(yán)密的一種授權(quán)模式逮栅,我以它為例采用的 koa2
悴势,自定義實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的 Authorization Code
授權(quán)方案。
主要思路還是通過(guò) client
引導(dǎo)用戶點(diǎn)擊進(jìn)入授權(quán)頁(yè)措伐,在授權(quán)頁(yè)面通過(guò)確認(rèn)授權(quán)后向后端請(qǐng)求 code
特纤, 重定向到 redirect_uri
, 并獲取服務(wù)端的 code
侥加,之后通過(guò) code
再去請(qǐng)求服務(wù)端獲取令牌 access_token
捧存,之后通過(guò) access_token
獲取用戶信息,整個(gè)效果如下圖所示:
這里我就不放代碼了担败,容易占地方N粞ā!詳情請(qǐng)戳這里
pass
:代碼里面的數(shù)據(jù)都是mock
的提前,還是有較多異常case
未做處理吗货,旨在了解整個(gè)授權(quán)的過(guò)程和實(shí)現(xiàn)思路,僅供參考
結(jié)語(yǔ)
OAuth
的授權(quán)方案目前已經(jīng)非常成熟狈网,在整個(gè)互聯(lián)網(wǎng)行業(yè)中也是非常常見(jiàn)的宙搬,早些年做微信生態(tài)的公眾號(hào)的時(shí)候初次接觸笨腥,到現(xiàn)在的深入了解,也算是一些進(jìn)步吧勇垛。
希望閱讀完本文也能讓你對(duì) OAuth
授權(quán)有一個(gè)深刻全面的認(rèn)識(shí)脖母,或者是加深鞏固 OAuth
授權(quán)方面的知識(shí)。
理論結(jié)合實(shí)踐闲孤,才是我們做為coder
應(yīng)有的追求谆级,加油!