第三方登入太常見了,微信,微博,QQ...總有一個你用過。固然看這篇文章的你,應該還用過github登入。這篇分享是在上一篇基於node的登入例子(node-koa-mongoose)的基礎增長了github帳號第三方受權登入功能,若是有些代碼,這篇中美介紹,你能夠先去看下上一篇的分享。html
本項目源碼地址:https://github.com/linwalker/...node
第三方登入主要基於OAuth 2.0。OAuth協議爲用戶資源的受權提供了一個安全的、開放而又簡易的標準。與以往的受權方式不一樣之處是OAUTH的受權不會使第三方觸及到用戶的賬號信息(如用戶名與密碼),即第三方無需使用用戶的用戶名與密碼就能夠申請得到該用戶資源的受權,所以OAUTH是安全的 ---- 百度百科git
更詳細的介紹能夠看這篇文章理解OAuth 2.0github
先來大體瞭解下第三方經過GitHub帳號受權登入的過程,具體實現結合後面代碼講解mongodb
1.獲取codejson
第三方客戶端向`https://github.com/login/oauth/authorize`發送get請求,帶上`?client_id=XXXXXX`參數,這時會跳轉到GitHub登入頁面,受權後GitHub會向客戶端返回`https://redirect_url?code=XXXXXX`。其中`client_id`和`redirect_url`是第三方事先在GitHub平臺上配置好的。
2.經過code獲取access_tokensegmentfault
客戶端處理`https://redirect_url?code=XXXXXX`請求,獲取code值,向`https://github.com/login/oauth/access_token`發起post請求,請求參數爲`client_di`,`client_secret`和`code`。
3.經過access_token獲取用戶GitHub帳號信息api
第二步的請求會返回這樣access_token=d0686dc49a22d64e77402db072b719f510f22421&scope=user&token_type=bearer
的內容,拿到access_token只須要向https://api.github.com/user?access_token=xxx
發送GET請求,便可獲取到登陸用戶的基本信息,跨域
首先你要有一個GitHub帳號,而後進入settings -> OAuth application -> Register a new application。進來後你會看到下面這個頁面:安全
依次填好應用名稱,應用地址和受權回掉地址後點擊Register application
按鈕,會生成一個client Id
和client Secret
,用於後面向GitHub發送請求傳參。
在頁面中添加GitHub登入跳轉按鈕,並在路由中對跳轉請求進行轉發處理:
//在node-login/components/LoginTab.js <a href="/github/login"> <Icon type="github" style={{fontSize: 20, color: '#000'}}/> </a>
添加跳轉按鈕後,增長相應路由處理,路由入口中添加/github路徑處理
//在node-login/routes/index.js const github = require('./github'); router.use('/github', github.routes(), github.allowedMethods());
最後是具體的路由處理
//在node-login/routes/github.js const config = require('../config'); const router = require('koa-router')(); const fetch = require('node-fetch'); const routers = router .get('/login', async (ctx) => { var dataStr = (new Date()).valueOf(); //重定向到認證接口,並配置參數 var path = "https://github.com/login/oauth/authorize"; path += '?client_id=' + config.client_id; path += '&scope=' + config.scope; path += '&state=' + dataStr; //轉發到受權服務器 ctx.redirect(path); }) module.exports = routers;
在config中事先添加配置請求所需參數client_id
,client_secret
和scope
。
module.exports = { 'database': 'mongodb://localhost:27017/node-login', 'client_id': '83b21756e93d6ce27075', 'client_secret': 'd87c4163ece5695a9ded1e8bf2701c5ee2651f28', 'scope': ['user'], };
其中scope參數可選。就是你期待你的應用須要調用Github哪些信息,能夠填寫多個,以逗號分割,好比:scope=user,public_repo。state參數非必需,用於防治跨域僞造請求攻擊。
如今能夠運行一下項目,點擊小黑貓,跳轉到受權登入頁面(沒登入過,要輸入帳號密碼),受權成功返回回掉地址。
回掉地址中code
就是返回的受權碼,經過受權碼再去獲取令牌access_token
。
在第一步受權請求https://github.com/login/oauth/authorize
成功後GitHub會給應用返回一個回掉http://localhost:3003/github/oauth/callback?code=14de2c737aa02037132d&state=1496989988474
。這個回掉地址就是以前在GitHub註冊應用時填入的回掉地址,另外還帶了須要的code參數,state就是上一步請求中帶的state參數,原樣返回。
如今咱們要對這個回掉請求進行處理:
//node-login/routes/github.js const config = require('../config'); const router = require('koa-router')(); const fetch = require('node-fetch'); const routers = router .get('/login', async (ctx) => { ... }) .get('/oauth/callback', async (ctx) => { const code = ctx.query.code; let path = 'https://github.com/login/oauth/access_token'; const params = { client_id: config.client_id, client_secret: config.client_secret, code: code } console.log(code); await fetch(path, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }) .then(res => { return res.text(); }) .then(body => { ctx.body = body; }) .catch(e => { console.log(e); }) }) module.exports = routers;
GitHub返回回掉地址時,先拿到請求中的code參數,而後向https://github.com/login/oauth/access_token
發送post請求並帶上client_id,client_secret,code
參數,請求成功後會返回帶有access_token的信息。
最後帶上獲取的access_token
請求https://api.github.com/user?access_token=xxx
,返回的就是以前scope中對應的帳號信息。
.get('/oauth/callback', async (ctx) => { const code = ctx.query.code; let path = 'https://github.com/login/oauth/access_token'; const params = { client_id: config.client_id, client_secret: config.client_secret, code: code } console.log(code); await fetch(path, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }) .then(res => { return res.text(); }) .then(body => { const args = body.split('&'); let arg = args[0].split('='); const access_token = arg[1]; console.log(body); console.log(access_token); return access_token; }) .then(async(token) => { const url = ' https://api.github.com/user?access_token=' + token; console.log(url); await fetch(url) .then(res => { return res.json(); }) .then(res => { console.log(res); ctx.body = res; }) }) .catch(e => { console.log(e); }) })
返回的用戶信息以下:
用一張圖來總結