本文將以用戶使用 github 登錄網(wǎng)站留言為例,簡(jiǎn)述 OAuth 2.0 的運(yùn)作流程。
假如我有一個(gè)網(wǎng)站罢杉,你是我網(wǎng)站上的訪客粪小,看了文章想留言表示「朕已閱」大磺,留言時(shí)發(fā)現(xiàn)有這個(gè)網(wǎng)站的帳號(hào)才能夠留言,此時(shí)給了你兩個(gè)選擇:一個(gè)是在我的網(wǎng)站上注冊(cè)擁有一個(gè)新賬戶探膊,然后用注冊(cè)的用戶名來留言杠愧;一個(gè)是使用 github 帳號(hào)登錄,使用你的 github 用戶名來留言逞壁。前者你覺得過于繁瑣流济,于是慣性地點(diǎn)擊了 github 登錄按鈕,此時(shí) OAuth 認(rèn)證流程就開始了腌闯。
需要明確的是绳瘟,即使用戶剛登錄過 github,我的網(wǎng)站也不可能向 github 發(fā)一個(gè)什么請(qǐng)求便能夠拿到訪客信息姿骏,這顯然是不安全的糖声。就算用戶允許你獲取他在 github 上的信息,github 為了保障用戶信息安全分瘦,也不會(huì)讓你隨意獲取蘸泻。所以操作之前,我的網(wǎng)站與 github 之間需要要有一個(gè)協(xié)商擅腰。
- 網(wǎng)站和 Github 之間的協(xié)商
Github 會(huì)對(duì)用戶的權(quán)限做分類蟋恬,比如讀取倉庫信息的權(quán)限、寫入倉庫的權(quán)限趁冈、讀取用戶信息的權(quán)限歼争、修改用戶信息的權(quán)限等等拜马。如果我想獲取用戶的信息,Github 會(huì)要求我沐绒,先在它的平臺(tái)上注冊(cè)一個(gè)應(yīng)用俩莽,在申請(qǐng)的時(shí)候標(biāo)明需要獲取用戶信息的哪些權(quán)限,用多少就申請(qǐng)多少乔遮,并且在申請(qǐng)的時(shí)候填寫你的網(wǎng)站域名扮超,Github 只允許在這個(gè)域名中獲取用戶信息。
此時(shí)我的網(wǎng)站已經(jīng)和 Github 之間達(dá)成了共識(shí)蹋肮,Github 也給我發(fā)了兩張門票出刷,一張門票叫做 Client Id,另一張門票叫做 Client Secret坯辩。
- 用戶和 Github 之間的協(xié)商
用戶進(jìn)入我的網(wǎng)站馁龟,點(diǎn)擊 github 登錄按鈕的時(shí)候,我的網(wǎng)站會(huì)把上面拿到的 Client Id 交給用戶漆魔,讓他進(jìn)入到 Github 的授權(quán)頁面坷檩,Github 看到了用戶手中的門票,就知道這是我的網(wǎng)站讓他過來的改抡,于是它就把我的網(wǎng)站想要獲取的權(quán)限擺出來矢炼,并詢問用戶是否允許我獲取這些權(quán)限。
// 用戶登錄 github阿纤,協(xié)商
GET https://github.com/login/oauth/authorize
// 協(xié)商憑證
params = {
client_id: "xxxx",
redirect_uri: "http://my-website.com"
}
如果用戶覺得我的網(wǎng)站要的權(quán)限太多句灌,或者壓根就不想我知道他這些信息,選擇了拒絕的話欠拾,整個(gè) OAuth 2.0 的認(rèn)證就結(jié)束了涯塔,認(rèn)證也以失敗告終。如果用戶覺得 OK清蚀,在授權(quán)頁面點(diǎn)擊了確認(rèn)授權(quán)后,頁面會(huì)跳轉(zhuǎn)到我預(yù)先設(shè)定的 redirect_uri 并附帶一個(gè)蓋了章的門票 code爹谭。
// 協(xié)商成功后帶著蓋了章的 code
Location: http://my-website.com?code=xxx
這個(gè)時(shí)候枷邪,用戶和 Github 之間的協(xié)商就已經(jīng)完成,Github 也會(huì)在自己的系統(tǒng)中記錄這次協(xié)商诺凡,表示該用戶已經(jīng)允許在我的網(wǎng)站訪問上直接操作和使用他的部分資源东揣。
- 告訴 Github 我的網(wǎng)站要來拜訪了
第二步中,我們已經(jīng)拿到了蓋過章的門票 code腹泌,但這個(gè) code 只能表明嘶卧,用戶允許我的網(wǎng)站從 github 上獲取該用戶的數(shù)據(jù),如果我直接拿這個(gè) code 去 github 訪問數(shù)據(jù)一定會(huì)被拒絕凉袱,因?yàn)槿魏稳硕伎梢猿钟?code芥吟,github 并不知道 code 持有方就是我本人侦铜。
還記得之前申請(qǐng)應(yīng)用的時(shí)候 github 給我的兩張門票么,Client Id 在上一步中已經(jīng)用過了钟鸵,接下來輪到另一張門票 Client Secret钉稍。
// 網(wǎng)站和 github 之間的協(xié)商
POST https://github.com/login/oauth/access_token
// 協(xié)商憑證包括 github 給用戶蓋的章和 github 發(fā)給我的門票
params = {
code: "xxx",
client_id: "xxx",
client_secret: "xxx",
redirect_uri: "http://my-website.com"
}
拿著用戶蓋過章的 code 和能夠標(biāo)識(shí)個(gè)人身份的 client_id、client_secret 去拜訪 github棺耍,拿到最后的綠卡 access_token贡未。
// 拿到最后的綠卡
response = {
access_token: "e72e16c7e42f292c6912e7710c838347ae178b4a"
scope: "user,gist"
token_type: "bearer",
refresh_token: "xxxx"
}
- 用戶開始使用 github 帳號(hào)在我的頁面上留言
// 訪問用戶數(shù)據(jù)
GET https://api.github.com/user?access_token=e72e16c7e42f292c6912e7710c838347ae178b4a
上一步 github 已經(jīng)把最后的綠卡 access_token 給我了,通過 github 提供的 API 加綠卡就能夠訪問用戶的信息了蒙袍,能獲取用戶的哪些權(quán)限在 response 中也給了明確的說明俊卤,scope 為 user 和 gist,也就是只能獲取 user 組和 gist 組兩個(gè)小組的權(quán)限害幅,user 組中就包含了用戶的名字和郵箱等信息了消恍。
// 告訴我用戶的名字和郵箱
response = {
username: "barretlee",
email: "barret.china@gmail.com"
}
整個(gè) OAuth2 流程在這里也基本完成了,文章中的表述很粗糙矫限,比如 access_token 這個(gè)綠卡是有過期時(shí)間的哺哼,如果過期了需要使用 refresh_token 重新簽證。重點(diǎn)是讓讀者理解整個(gè)流程叼风,細(xì)節(jié)部分可以閱讀 RFC6749 文檔取董。
希望對(duì)你理解 OAuth 2.0 有幫助。(本文完)
本文鏈接:http://www.barretlee.com/blog/2016/01/10/oauth2-introduce/