記錄最近作的一個 demo,前端使用 React
,用 React Router
實現前端路由,Koa 2
搭建 API Server, 最後經過 Nginx
作請求轉發。前端
第一篇:React + Node 單頁應用「一」前端搭建
React + Node 單頁應用「二」OAuth 2.0 受權認證 & GitHub 受權實踐node
這是第二篇,介紹下 OAuth 2.0
受權機制,以及 Github App 受權過程,經過獲取受權使用 Github API。react
傳統的 CS(Client-Server) 受權模式下,請求訪問受保護資源(用戶信息)時,客戶端須要向服務器提供資源所屬用戶的證書,爲了讓第三方拿到資源,用戶就得將證書共享給第三方應用。這種方式會致使如下幾個問題:ios
爲了解決這個問題,OAuth 協議引入了受權層,並將客戶端與服務端的角色區分開,在 OAuth 協議中,客戶端請求的 Access_token
,被託管在資源服務器,但受用戶控制,而且與用戶憑證徹底不一樣。git
舉個例子,如今有一家檔案館,檔案館中有不少資料,這些資料有些涉及到機密,有些只是常規資料,
研究員小李須要進入檔案館查找常規資料,因而就跑去找羅館長批條子github
「館長館長,我要看一些常規資料,請給我批個條子吧」json
羅館長了解了小李要看的是常規資料,很爽快地批了axios
「沒問題,給,這是贊成的條子」跨域
因而小李拿到條子後,徑直去找了檔案館門衛大壯
「大壯,你看這是館長給我批的查看常規資料的條子」,
大壯確認沒問題後
「嗯,既然館長贊成了,來,這是常規文件的鑰匙」,
因而小李就拿着鑰匙進入館內開始找資料,館內每道房門都有一把鎖,若是房間裏存放的是常規資料,小李只須要出示鑰匙就能夠進入,但存放涉密資料的房間,小李的鑰匙打不開,必須找館長批一份查看涉密資料的條子,再拿着條子去大壯那兒換一把新的鑰匙。
資源全部者
能夠受權獲取受保護資源的實體,若是這個全部者是人,即常規意義的用戶,即檔案館的館長。
資源服務器
資源服務器用於存儲資源,接收請求,並將資源返回給攜帶合法 Access_token
的請求,在咱們的例子中,檔案館就充當着資源服務器的角色。
客戶端
獲取受權後,表明用戶請求資源的第三方應用,也就是故事中的研究員小李。
受權服務器
受權服務器在成功認證資源擁有者並獲取到受權後,發放 Access_token
給客戶端,故事中大壯的主要工做內容就是發放訪問鑰匙。
/** * 協議流程 * 引自 RFC6749 */ +--------+ +---------------+ | |--(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 ---| | +--------+ +---------------+
上面這張圖是引自 RFC6749 的 OAuth 2.0 受權流程,歸納以下
Access_token
Access_token
,第三方應用就能夠訪問資源服務器中的資源了Github 有一套很是完備的 API,在沒有得到受權時,僅有部分功能可用,例如獲取用戶信息、倉庫信息等,而且調用次數被限制在了一小時僅容許60次
受權後,每小時調用次數放開到每小時 5000 次,而且申請受權時,能夠選擇申請的權限範圍,例如申請 star 項目、follow 用戶的權限(咱們此次用到的)等等,咱們經過申請完整的權限,甚至能夠寫一個 Github 第三方應用。
要獲取受權,首先須要在 Github 註冊一個應用,註冊這個應用以前,須要準備好兩個東西
github.lijundong.com
(若是是 IP 記得加協議頭)github.lijundong.com/github/getauth
可依照如下路徑建立一個受權 APP,
Github > setting > Developer settings > OAuth Apps > New OAuth App
進入註冊界面,須要填寫應用名、應用主頁地址、應用簡介、以及回調 URL,建立完成會跳轉到 APP 管理頁面,在管理頁面能夠更新應用信息以及上傳應用 Logo,而且你將看到你的應用的 Client ID
、Client Secret
,接下來獲取權限須要用到這兩個東西。
GitHub 官方的受權流程:
第一步:頁面跳轉到 GitHub 的受權頁
在項目中,我選擇了用 <a>
標籤連接的方式跳轉。
GET https://github.com/login/oauth/authorize?client_id=xxx&scope=xxx /** * client_id:註冊應用的 client_id 必填 * scope:申請的權限範圍 選填,默認用戶權限爲空 */
第二步:回調接口收到 GitHub 的回調請求,得到 code
咱們在註冊應用時,設置了受權回調 URL,上一步中,Github 受權頁成功得到用戶受權後,會帶上 code 請求咱們設置的回調 URL,在這一步中,咱們的 Server 就拿到了用戶的受權 code。
第三步:經過 code 獲取 Access_token
最後一步經過已有 code,加上應用的 client_id
和 client_secret
,咱們向 Github 申請 Access_token
。
/** * code:第二步獲取到的 code 必填 * client_secret:註冊應用 client_secret 必填 * client_id:註冊應用的 client_id 必填 */ const rp = require('request-promise') let option = { uri: 'https://github.com/login/oauth/access_token?client_id=' + clientId + '&client_secret=' + clientSecret + '&code=' + code, json: true } let tokenResp = await rp(option);
第四步:將得到的 Access_token
寫入頁面的 cookie 中。
ctx.cookies.set('access_token', tokenResp.access_token, { 'httpOnly': false })
由於第三方應用請求 GitHub API 涉及到跨域,第一篇文章已經提到了Github API 只支持 XHR 跨域請求,一些同窗若是用 Fetch 跨域請求 API 會致使請求 request type
變成 option
,因此項目中改用 axios
進行網絡請求。
這裏以獲取登錄用戶基本信息爲例,
import Axios from 'axios' import Cookie from 'js-cookie' const access_token = Cookie.get('access_token'); getLoginInfo() { let that = this; let url = API.GITHUB.GET_LOGIN_INFO; Axios.get(url, { params: { access_token: access_token } }).then(function(res) { that.setState({ loginInfo: res.data, }); }).catch(function (error) { console.error(error); }) }
參考: