电竞比分网-中国电竞赛事及体育赛事平台

分享

基于前后端分離的身份認證方式

 quasiceo 2018-09-07

目錄:
一、什么是JWT
二、我們?yōu)槭裁匆褂肑WT(與傳統(tǒng)的session認證有何區(qū)別)
三、如何使用JWT
四、JWT的構(gòu)成及原理
五、JWT加解密實例

一、什么是JWT
JWT——Json web token
是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn),可實現(xiàn)無狀態(tài)、分布式的Web應(yīng)用授權(quán)。

二、我們?yōu)槭裁葱枰狫WT?
首先,當(dāng)前后端分離時我們會因為同源策略而無法設(shè)置cookie和sessionid。當(dāng)然了我們有很多方式去解決這個問題,比如反向代理和jsonp等。但這仍然不如直接使用jwt來的簡便。其次就是要說到j(luò)wt與傳統(tǒng)的身份認證相比有什么優(yōu)勢了。
回答這個問題需要來看看基于token的認證和傳統(tǒng)的session認證的區(qū)別
1、傳統(tǒng)的session認證

我們知道,http協(xié)議本身是一種無狀態(tài)的協(xié)議,而這就意味著如果用戶向我們的應(yīng)用提供了用戶名和密碼來進行用戶認證,那么下一次請求時,用戶還要再一次進行用戶認證才行,因為根據(jù)http協(xié)議,我們并不能知道是哪個用戶發(fā)出的請求,所以為了讓我們的應(yīng)用能識別是哪個用戶發(fā)出的請求,我們只能在服務(wù)器存儲一份用戶登錄的信息,這份登錄信息會在響應(yīng)時傳遞給瀏覽器,告訴其保存為cookie,以便下次請求時發(fā)送給我們的應(yīng)用,這樣我們的應(yīng)用就能識別請求來自哪個用戶了,這就是傳統(tǒng)的基于session認證。

但是這種基于session的認證使應(yīng)用本身很難得到擴展,隨著不同客戶端用戶的增加,獨立的服務(wù)器已無法承載更多的用戶,而這時候基于session認證應(yīng)用的問題就會暴露出來.

2、基于token的鑒權(quán)機制

基于token的鑒權(quán)機制類似于http協(xié)議也是無狀態(tài)的,它不需要在服務(wù)端去保留用戶的認證信息或者會話信息。這就意味著基于token認證機制的應(yīng)用不需要去考慮用戶在哪一臺服務(wù)器登錄了,這就為應(yīng)用的擴展提供了便利。

流程上是這樣的:

1、用戶使用用戶名密碼來請求服務(wù)器 2、
2、服務(wù)器進行驗證用戶的信息 服務(wù)器通過驗證發(fā)送給用戶一個token
3、 客戶端存儲token,并在每次請求時附送上這個token值 服務(wù)端驗證token值,并返回數(shù)據(jù)
4、這個token必須要在每次請求時傳遞給服務(wù)端,它應(yīng)該保存在請求頭里,
另外,服務(wù)端要支持CORS(跨來源資源共享)策略,一般我們在服務(wù)端這么做就可以了Access-Control-Allow-Origin:*。

也就是說相比于傳統(tǒng)基于cookie的session,基于token的jwt有以下優(yōu)點:

Cookie是不允許垮域訪問的,這一點對Token機制是不存在的,前提是傳輸?shù)挠脩粽J證信息通過HTTP頭傳輸.
無狀態(tài)(也稱:服務(wù)端可擴展行):Token機制在服務(wù)端不需要存儲session信息,因為Token 自身包含了所有登錄用戶的信息,只需要在客戶端的cookie或本地介質(zhì)存儲狀態(tài)信息.
更適用CDN: 可以通過內(nèi)容分發(fā)網(wǎng)絡(luò)請求你服務(wù)端的所有資料(如:javascript,HTML,圖片等),而你的服務(wù)端只要提供API即可.
去耦: 不需要綁定到一個特定的身份驗證方案。Token可以在任何地方生成,只要在你的API被調(diào)用的時候,你可以進行Token生成調(diào)用即可.
更適用于移動應(yīng)用: 當(dāng)你的客戶端是一個原生平臺(iOS, Android,Windows 8等)時,Cookie是不被支持的(你需要通過Cookie容器進行處理),這時采用Token認證機制就會簡單得多。
CSRF:因為不再依賴于Cookie,所以你就不需要考慮對CSRF(跨站請求偽造)的防范。
性能: 一次網(wǎng)絡(luò)往返時間(通過數(shù)據(jù)庫查詢session信息)總比做一次HMACSHA256計算 的Token驗證和解析要費時得多.
不需要為登錄頁面做特殊處理: 如果你使用Protractor 做功能測試的時候,不再需要為登錄頁面做特殊處理.
基于標(biāo)準(zhǔn)化:你的API可以采用標(biāo)準(zhǔn)化的 JSON Web Token (JWT). 這個標(biāo)準(zhǔn)已經(jīng)存在多個后端庫(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).

三、如何使用jwt

安裝方式:

//--save是否需要取決于你是否需要把安裝版本寫進package.json
npm install --save)jwt-simple
  • 1
  • 2
  • 3

使用方式

var jwt = require('jwt-simple');
var payload = { foo: 'bar' };
var secret = 'xxx';

// HS256 secrets are typically 128-bit random strings, for example hex-encoded: 
// var secret = Buffer.from('fe1a1915a379f3be5394b64d14794932', 'hex) 

// encode 
var token = jwt.encode(payload, secret);

// decode 
var decoded = jwt.decode(token, secret);
console.log(decoded); //=> { foo: 'bar' } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意secret是用于解密的密文,是必須保存在服務(wù)器端。

四、JWT的原理及構(gòu)成
JWT的構(gòu)成:
jwt由三部分構(gòu)成:頭部(header)、載荷(payload, )、簽證(signature).

頭部:jwt的頭部承載兩部分信息:

聲明類型,這里是jwt
聲明加密的算法 通常直接使用 HMAC SHA256
完整的頭部就像下面這樣的JSON:

{
  'typ': 'JWT',
  'alg': 'HS256'
}
  • 1
  • 2
  • 3
  • 4

然后將頭部進行base64加密(該加密是可以對稱解密的),構(gòu)成了第一部分.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
playload
  • 1
  • 2

載荷:就是存放有效信息的地方。,這些有效信息包含三個部分

標(biāo)準(zhǔn)中注冊的聲明
公共的聲明
私有的聲明
標(biāo)準(zhǔn)中注冊的聲明 (建議但不強制使用) :

iss: jwt簽發(fā)者
sub: jwt所面向的用戶
aud: 接收jwt的一方
exp: jwt的過期時間,這個過期時間必須要大于簽發(fā)時間
nbf: 定義在什么時間之前,該jwt都是不可用的.
iat: jwt的簽發(fā)時間
jti: jwt的唯一身份標(biāo)識,主要用來作為一次性token,從而回避重放攻擊。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

公共的聲明 :
公共的聲明可以添加任何的信息,一般添加用戶的相關(guān)信息或其他業(yè)務(wù)需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.

私有的聲明 :
私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。

定義一個payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}
  • 1
  • 2
  • 3
  • 4
  • 5

然后將其進行base64加密,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
signature
  • 1
  • 2

簽證:這個簽證信息由三部分header (base64后的)
payload (base64后的)
secret分需要base64加密后的header和base64加密后的payload使用.連接組成的字符串,然后通過header中聲明的加密方式進行加鹽secret組合加密,然后就構(gòu)成了jwt的第三部分。

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
  • 1
  • 2
  • 3
  • 4

將這三部分用.連接成一個完整的字符串,構(gòu)成了最終的jwt:

五、jwt運用實例

/**
 * 身份驗證.
 */
const jwt = require('jwt-simple');
const moment = require('moment');

//加密過程
var getJwt = function(userId,secret)
{
  var expires = moment().add( 7,'days').valueOf();
  var token = jwt.encode({
    iss: userId,
    exp: expires
  }, secret);
  return token;
}

//解密過程
var testJwt = function(token,secret){
  //返回{foo: 'bar'}
  var decoded = jwt.decode(token,secret)
  return decoded;
}

module.exports = {
  create: getJwt,
  test: testJwt
}

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多