什么是Token?
在計算機身份認證中是令牌(臨時)的意思,在詞法分析中是標記的意思。一般我們所說的的token大多是指用於身份驗證的token
Token的特點
- 隨機性
- 不可預測性
- 時效性
- 無狀態、可擴展
基於Token的身份驗證方法
- 客戶端使用用戶名和密碼請求登錄
- 服務端收到請求,驗證登錄是否成功
- 驗證成功后,服務端會返回一個Token給客戶端,反之,返回身份驗證失敗的信息
- 客戶端收到Token后把Token用一種方式(cookie/localstorage/sessionstorage/其他)存儲起來
- 客戶端每次發起請求時都選哦將Token發給服務端
- 服務端收到請求后,驗證Token的合法性,合法就返回客戶端所需數據,反之,返回驗證失敗的信息
JWT(Json Web Tokens)
生成Token的解決方案有許多,常用的一種就是 Json Web Tokens .
JWT標准的Tokens由三部分組成
- header
- payload
- signature
中間使用 " . " 分隔開,並且都會使用Base64編碼方式編碼,如下
eyJhbGc6IkpXVCJ9.eyJpc3MiOiJCIsImVzg5NTU0NDUiLCJuYW1lnVlfQ.SwyHTf8AqKYMAJc
header
header 部分主要是兩部分內容,一個是 Token 的類型,另一個是使用的算法,比如下面類型就是 JWT,使用的算法是 Hash256。
{
"typ": "JWT",
"alg": "HS256"
}
payload
Payload 里面是 Token 的具體內容,這些內容里面有一些是標准字段,你也可以添加其它需要的內容。下面是標准字段:
- iss:Issuer,發行者
- sub:Subject,主題
- aud:Audience,觀眾
- exp:Expiration time,過期時間
- nbf:Not before
- iat:Issued at,發行時間
- jti:JWT ID
比如下面
{
"iss": "ninghao.net",
"exp": "1438955445",
"name": "wanghao",
"admin": true
}d
signature
JWT 的最后一部分是 Signature ,這部分內容有三個部分,先是拼接 Base64 編碼的 header.payload ,再用不可逆的Hamc加密算法加密,加密時使用一個密鑰,這個密鑰服務端保存,生成signature。
最后組合token,如下
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.
SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
客戶端收到這個 Token 以后把它存儲下來,下回向服務端發送請求的時候就帶着這個 Token 。服務端收到這個 Token ,然后進行驗證,通過以后就會返回給客戶端想要的資源。
Nodejs實現
token.js
var crypto=require("crypto");
var token={
createToken:function(obj,timeout){
console.log(parseInt(timeout)||0);
var obj2={
data:obj,//payload
created:parseInt(Date.now()/1000),//token生成的時間的,單位秒
exp:parseInt(timeout)||10//token有效期
};
//payload信息
var base64Str=Buffer.from(JSON.stringify(obj2),"utf8").toString("base64");
//添加簽名,防篡改
var secret="hel.h-five.com";
var hash=crypto.createHmac('sha256',secret);
hash.update(base64Str);
var signature=hash.digest('base64');
return base64Str+"."+signature;
},
decodeToken:function(token){
var decArr=token.split(".");
if(decArr.length<2){
//token不合法
return false;
}
var payload={};
//將payload json字符串 解析為對象
try{
payload=JSON.parse(Buffer.from(decArr[0],"base64").toString("utf8"));
}catch(e){
return false;
}
//檢驗簽名
var secret="hel.h-five.com";
var hash=crypto.createHmac('sha256',secret);
hash.update(decArr[0]);
var checkSignature=hash.digest('base64');
return {
payload:payload,
signature:decArr[1],
checkSignature:checkSignature
}
},
checkToken:function(token){
var resDecode=this.decodeToken(token);
if(!resDecode){
return false;
}
//是否過期
var expState=(parseInt(Date.now()/1000)-parseInt(resDecode.payload.created))>parseInt(resDecode.payload.exp)?false:true;
if(resDecode.signature===resDecode.checkSignature&&expState){
return true;
}
return false;
}
}
module.exports=exports=token;