網絡上關於Oauth 2.0協議的基本內容已經不少了,我就不重複寫博客了,對基本概念不理解的同窗能夠先自行Google。可是我發現實際演示的demo不多,因此寫了這個偏實戰的博客。css
其實OAuth認證說白了:html
GitHub,用戶,第三方網站third-sidenode
經用戶贊成,讓third-side安全的從GitHub拿到一個tokengit
third-side拿到這個token能夠用來github
一個application對應一個項目,咱們須要拿到一個client id 和 secret來用於後續的登陸認證數據庫
由於咱們要使用GitHub做爲第三方登陸,因此確定要先到官網上註冊一個application。express
點擊綠色的按鈕就好了,點擊後會出現👇的頁面:瀏覽器
上面的內容不少,可是隻有兩個字段是關鍵的安全
Application Name
: 這個是GitHub 用來標識咱們的APP的Authorization callback url
:就是上面我特地用紅色字體標識的的,很關鍵這個Authorization callback url
就是在用戶確認登陸後,GitHub會經過這個url來告知咱們的服務器。因此真實狀況下這個url應該是由專門的服務器程序來監聽的。可是這一步你們能夠先跟着我填寫,後面細細說。服務器
完成註冊後,咱們就有了這些數據:
上面有兩個數據很關鍵
cliendt_id
這是GitHub用來標識咱們的APP的接下來咱們須要經過這個字段來構建咱們的登陸url
client Secret
這個很關鍵,等會咱們就靠它來認證的,要好好保存。我這個只是演示教程,用完就銷燬了,因此直接公開了。而後咱們接下來怎麼作?很簡單
<body> <a href="https://github.com/login/oauth/authorize\ ?client_id=47878c9a96cfc358eb6e"> login with github</a> </body>
咱們只要在咱們的登陸頁面添加這樣的代碼,引導用戶點擊咱們的登陸按鈕就好了。
注意到上面的流程了嗎? 其實咱們已經完成了一半的登陸認證流程了,而後咱們來分析一下。
首先請你們思考一下:從用戶點擊login with github
開始,中間有幾回重要的HTTP報文傳遞?
不重要是指中間那些網頁中附帶的對css js資源的請求,這些不算。
與登陸認證有關的http請求有幾個?
3個!!!說清楚這一點,基本就明白了。
首先咱們構造了這樣的html頁面
<body> <a href="https://github.com/login/oauth/authorize\ ?client_id=47878c9a96cfc358eb6e"> login with github</a> </body>
關鍵是咱們構造了一個url
https://github.com/login/oauth/authorize
:這一部分是固定的,只要是用GitHub登陸,就得這樣。你能夠從官方文檔上看到這個連接。
若是是微信登陸,twitter登陸,也是大同小異,具體的url能夠在相關的官網上找到。
GitHub會監聽這個路由,來作出登陸處理
client_id=47878c9a96cfc358eb6e
。它的值就是咱們以前申請到的client id。這是個必須存在的字段,用戶點擊登陸後,GitHub就是經過這個字段來確認用戶到底是想登陸哪一個網站。
而後GitHub會返回這樣的頁面,確認用戶是否真的要登陸,這就是第一次HTTP請求和響應
而後用戶點擊確認後發生了什麼?
這個是第二次HTTP請求和響應。由於瀏覽器收到301重定向後,會直接前往新的網址了,因此你要是沒仔細看的話,可能就忽略了。
這個狀態碼爲301的報文,它的Location字段大概長這樣:https://github.com/fish56/OAuth?code=a1aee8cacf7560825665>
https://github.com/fish56/OAuth
這個字段就是咱們以前填寫的callback url,正常狀況下這個應該是咱們雲服務器的網址。可是這裏爲了演示方便,我這裏就隨便填寫了個人github地址,不要緊的
code=a1aee8cacf7560825665
:(由於筆者中間調試過,因此如今寫的token和gif裏面的不同哈)
這個就是咱們OAuth登陸的一個核心信息。我以前說過,咱們OAuth登陸的核心目的就是讓第三方網站可以安全的拿到用戶的token。用戶的瀏覽器收到以前的301的HTTP響應後,就會向咱們服務器發起請求,請求的同時服務器就拿到了這個code。服務器就能夠經過這個code從github拿到用戶的token。
這就是第三次http請求。
而後又有同窗可能會問了,爲何要返回一個code,而不是直接返回一個token呢?
答:爲了安全,若是token通過用戶的手裏走一遍,就可能會被其餘惡意的人竊取。
OAuth協議下,GitHub會返回給用戶一個code,而後用戶瀏覽器經過重定向攜帶這個code來訪問咱們的服務器,這樣服務器就拿到了這個code。
服務器拿到這個code 以後,經過結合以前的client secret向GitHub申請token,這樣會安全一點。
以前咱們只作了一半, 接下來咱們經過postman來演示一下如何經過code拿到token。
咱們要向GitHub申請用戶的token,須要
這個只有在用戶贊成登陸後,服務器才能拿到。
https://github.com/login/oauth/access_token
發起POST請求,而且攜帶上面的三個字段這個url是GitHub規定的,你能夠在它的官方文檔中找到
而後咱們在postman中構造這樣的請求:
哎,能夠看到,這咱們確實拿到了用戶的token:
access_token=9094eb58a23093fd593d43eb28c1f06ce7904ed5&scope=&token_type=bearer
。
只不過真實狀況下上面的操做都是由線上的服務器完成的,我這樣操做是方便你們的理解。
經過上面的例子咱們能夠看到,若是隻是演示,咱們是不須要服務器。接下來咱們在本地用代碼直接演示下。
由於咱們要啓動本地的服務器來監聽響應,因此咱們首先要修改下咱們的callback URL。
請你們將這個callback URL自行修改成http://localhost:8099/github/login
。
這是咱們程序的目錄結構
而後這是咱們的node代碼:
const querystring = require('querystring'); const express = require('express'); const request = require('request'); const githubConfig = require('./oauth.conf') let app = express(); // 作一個路由函數,監聽/github/login 的get請求 app.get('/github/login', async function(req,res){ //read code from url let code = req.query.code // 收到code後,向GitHub請求用戶的token request.post(githubConfig.access_token_url, { form:{ client_id: githubConfig.client_ID, client_secret: githubConfig.client_Secret, code: code } },function(error, response, body) { //正常狀況下,返回值應該是形如access_token=9094eb58a23093fd59 // 3d43eb28c1f06ce7904ed5&scope=&token_type=bearer // 的字符串,能夠經過下面的函數來解析 let result = querystring.parse(body) // 拿到token後,返回結果,表示咱們成功了 let access_token = result["access_token"] if(access_token == undefined){ res.send(result.error_description) } res.send(`You are login! you token is ${access_token}`) }) }) // 監聽 8999 ,啓動程序。注意端口號要和咱們以前填寫的保持一致 app.listen(8099,function(){ console.log('listening localhost:8099') })
這是oauth.conf.js
。注意把相關的字段換成你本身的配置。
module.exports = { client_ID: '47878c9a96cfc358eb6e', client_Secret: '4813689c043c60dbf3d3a0d8e0a984afc0bf810a', access_token_url: 'https://github.com/login/oauth/access_token' }
這是實際效果
咱們的代碼作了什麼事?只是把咱們以前的手動使用postman作的事情自動化了
http://localhost:8099/github/login
不過其實我上面省略了不少操做。正常狀況下,服務器拿到用戶的token後,應該:
好了,上面基本就是一次登陸流程。