定義
- OAuth是一個關(guān)于授權(quán)(authorization)的開放網(wǎng)絡(luò)標(biāo)準(zhǔn)涣狗,在全世界得到廣泛應(yīng)用,目前的版本是2.0版
舉例: OAuth 就是一種授權(quán)機制跪呈。數(shù)據(jù)的所有者告訴系統(tǒng)妇汗,同意授權(quán)第三方應(yīng)用進(jìn)入系統(tǒng)孩革,獲取這些數(shù)據(jù)际歼。系統(tǒng)從而產(chǎn)生一個短期的進(jìn)入令牌(token)惶翻,用來代替密碼,供第三方應(yīng)用使用鹅心。 - 令牌(token)與密碼(password)
相同點
作用是一樣的吕粗,都可以進(jìn)入系統(tǒng),但是有三點差異
不同點
(1)令牌是短期的巴帮,到期會自動失效溯泣,用戶自己無法修改虐秋。密碼一般長期有效榕茧,用戶不修改,就不會發(fā)生變化客给。
(2)令牌可以被數(shù)據(jù)所有者撤銷用押,會立即失效。以上例而言靶剑,屋主可以隨時取消快遞員的令牌蜻拨。密碼一般不允許被他人撤銷。
(3)令牌有權(quán)限范圍(scope)桩引,比如只能進(jìn)小區(qū)的二號門缎讼。對于網(wǎng)絡(luò)服務(wù)來說,只讀令牌就比讀寫令牌更安全坑匠。密碼一般是完整權(quán)限血崭。 - 令牌使用
A 網(wǎng)站拿到令牌以后,就可以向 B 網(wǎng)站的 API 請求數(shù)據(jù)了
每個發(fā)到 API 的請求,都必須帶有令牌
具體做法是在請求的頭信息夹纫,加上一個Authorization字段咽瓷,令牌就放在這個字段里面。
curl -H "Authorization: Bearer ACCESS_TOKEN" \"[https://api.b.com](https://api.b.com/)"
上面命令中舰讹,ACCESS_TOKEN就是拿到的令牌茅姜。
- 令牌更新
令牌的有效期到了
具體方法是,B 網(wǎng)站頒發(fā)令牌的時候月匣,一次性頒發(fā)兩個令牌钻洒,一個用于獲取數(shù)據(jù),另一個用于獲取新的令牌(refresh token 字段)桶错。令牌到期前航唆,用戶使用 refresh token 發(fā)一個請求,去更新令牌院刁。B 網(wǎng)站驗證通過以后糯钙,就會頒發(fā)新的令牌。
https://b.com/oauth/token?grant_type=refresh_token&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN
上面 URL 中退腥,grant_type參數(shù)為refresh_token表示要求更新令牌任岸,client_id參數(shù)和client_secret參數(shù)用于確認(rèn)身份,refresh_token參數(shù)就是用于更新令牌的令牌狡刘。
4種授權(quán)方式
舉例:授權(quán)碼
第一步享潜,A 網(wǎng)站提供一個鏈接,用戶點擊后就會跳轉(zhuǎn)到 B 網(wǎng)站嗅蔬,授權(quán)用戶數(shù)據(jù)給 A 網(wǎng)站使用剑按。下面就是 A 網(wǎng)站跳轉(zhuǎn) B 網(wǎng)站的一個示意鏈接。
https://b.com/oauth/authorize?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read
上面 URL 中澜术,response_type參數(shù)表示要求返回授權(quán)碼(code)艺蝴,client_id參數(shù)讓 B 知道是誰在請求,redirect_uri參數(shù)是 B 接受或拒絕請求后的跳轉(zhuǎn)網(wǎng)址鸟废,scope參數(shù)表示要求的授權(quán)范圍(這里是只讀)猜敢。
第二步,用戶跳轉(zhuǎn)后盒延,B 網(wǎng)站會要求用戶登錄缩擂,然后詢問是否同意給予 A 網(wǎng)站授權(quán)。用戶表示同意添寺,這時 B 網(wǎng)站就會跳回redirect_uri參數(shù)指定的網(wǎng)址胯盯。跳轉(zhuǎn)時,會傳回一個授權(quán)碼计露,就像下面這樣
https://a.com/callback?code=AUTHORIZATION_CODE
上面 URL 中博脑,code參數(shù)就是授權(quán)碼楞捂。
第三步,A 網(wǎng)站拿到授權(quán)碼以后趋厉,就可以在后端寨闹,向 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
上面 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)站收到請求以后,就會頒發(fā)令牌玖翅。具體做法是向redirect_uri指定的網(wǎng)址翼馆,發(fā)送一段 JSON 數(shù)據(jù)。
{
"access_token":"ACCESS_TOKEN",
"token_type":"bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN",
"scope":"read",
"uid":100101,
"info":{...}
}
上面 JSON 數(shù)據(jù)中金度,access_token字段就是令牌应媚,A 網(wǎng)站在后端拿到了。
Demo
下載源碼
源碼github鏈接: 網(wǎng)上提供的代碼倉庫猜极,請將它克隆到本地中姜。
$ git clone git@github.com:ruanyf/node-oauth-demo.git
$ cd node-oauth-demo
兩個配置項要改一下,寫入上一步的身份識別碼跟伏。
index.js
:改掉變量clientID
andclientSecret
public/index.html
:改掉變量client_id
然后丢胚,安裝依賴。
$ npm install
啟動服務(wù)受扳。
$ node index.js
瀏覽器訪問[http://localhost:8080](http://localhost:8080/)
携龟,就可以看到這個示例了。
查看授權(quán)頁面
示例的首頁很簡單辞色,就是一個鏈接骨宠,讓用戶跳轉(zhuǎn)到 GitHub浮定。
跳轉(zhuǎn)的 URL 如下相满。
https://github.com/login/oauth/authorize?
client_id=7e015d8ce32370079895&
redirect_uri=http://localhost:8080/oauth/redirect
這個 URL 指向 GitHub 的 OAuth 授權(quán)網(wǎng)址,帶有兩個參數(shù):client_id
告訴 GitHub 誰在請求克婶,redirect_uri
是稍后跳轉(zhuǎn)回來的網(wǎng)址绊谭。
用戶點擊到了 GitHub脖苏,GitHub 會要求用戶登錄,確保是本人在操作建蹄。
登錄后碌更,GitHub 詢問用戶,該應(yīng)用正在請求數(shù)據(jù)洞慎,你是否同意授權(quán)痛单。
[圖片上傳中...(code.png-7e7999-1645355031998-0)]
用戶同意授權(quán), GitHub 就會跳轉(zhuǎn)到redirect_uri
指定的跳轉(zhuǎn)網(wǎng)址劲腿,并且?guī)鲜跈?quán)碼旭绒,跳轉(zhuǎn)回來的 URL 就是下面的樣子。
http://localhost:8080/oauth/redirect?code=859310e7cecc9196f4af
后端收到這個請求以后焦人,就拿到了授權(quán)碼(code
參數(shù))挥吵。
后端實現(xiàn)
示例的后端采用 Koa 框架編寫,具體語法請看教程花椭。
這里的關(guān)鍵是針對/oauth/redirect
的請求忽匈,編寫一個路由,完成 OAuth 認(rèn)證矿辽。
const oauth = async ctx => { // ... }; app.use(route.get('/oauth/redirect', oauth));
上面代碼中丹允,oauth
函數(shù)就是路由的處理函數(shù)。下面的代碼都寫在這個函數(shù)里面袋倔。
路由函數(shù)的第一件事嫌松,是從 URL 取出授權(quán)碼。
const requestToken = ctx.request.query.code;
后端使用這個授權(quán)碼奕污,向 GitHub 請求令牌萎羔。
const tokenResponse = await axios({
method: 'post',
url: 'https://github.com/login/oauth/access_token?' +
`client_id=${clientID}&` +
`client_secret=${clientSecret}&` +
`code=${requestToken}`,
headers: {
accept: 'application/json'
}
});
上面代碼中,GitHub 的令牌接口[https://github.com/login/oauth/access_token](https://github.com/login/oauth/access_token)
需要提供三個參數(shù)碳默。
client_id
:客戶端的 IDclient_secret
:客戶端的密鑰code
:授權(quán)碼
作為回應(yīng)贾陷,GitHub 會返回一段 JSON 數(shù)據(jù),里面包含了令牌accessToken
嘱根。const accessToken = tokenResponse.data.access_token髓废;
API數(shù)據(jù)
有了令牌以后,就可以向 API 請求數(shù)據(jù)了该抒。
const result = await axios({
method: 'get',
url: `https://api.github.com/user`,
headers: {
accept: 'application/json',
Authorization: `token ${accessToken}`
}
});
上面代碼中慌洪,GitHub API 的地址是[https://api.github.com/user](https://api.github.com/user)
,請求的時候必須在 HTTP 頭信息里面帶上令牌Authorization: token 361507da
凑保。
然后冈爹,就可以拿到用戶數(shù)據(jù),得到用戶的身份欧引。
const name = result.data.name;
ctx.response.redirect(`/welcome.html?name=${name}`);
總結(jié):