NodeJS中的token

JWT

1、Token

  • 什麼是Token?web

    Token指訪問資源的憑據,是一種身份認證的方式,它是解決跨域認證的最流行的一種方式。算法

  • 爲何用Token?數據庫

    之前較爲流行的是經過session去作身份認證,session是經過服務器中保存會話數據來作身份認證,這種方式會致使在高併發中服務器壓力過大的狀況,還有就是,若是是服務器集羣,那麼就須要這些服務器session共享。express

    Token不在服務器中保存會話數據,而是保存在客戶端。每次請求的headers中存入Token,在服務器中判斷Token的有效性,是否能夠訪問資源。npm

  • 傳統Token和JWT的區別json

    • 傳統Tokenapi

      用戶發起登陸請求,登陸成功以後返回Token,而且存於數據庫,用戶訪問資源的時候須要攜帶Token,服務端獲取Token以後和數據庫中的對比。跨域

    • JWTbash

      用戶發起登陸請求,登陸成功以後返回Token,可是不存於數據庫,用戶訪問資源的時候須要攜帶Token,服務端獲取Token以後去校驗Token的合法性。服務器

2、JWT實現過程

  • JWT分爲三個部分header、payload、verify signature

  • header

    內部包含有簽名算法、Token類型,而後經過base64url算法轉成字符串

    //明文例子:
    {
        "alg":"HS256",
        "typ":"JWT"
    }
    複製代碼
  • payload

    內部包含JWT標準數據和自定義數據,而後經過base64url算法轉成字符串

    JWT標準數據常見的有:

    • iss:提供方。
    • sub:主題,通常是用戶ID。
    • exp:過時時間。
    • iat:建立時間。
    • jti:token的惟一標識。

    可選擇性使用以上標準數據

    //明文例子:
    {
      "id": 3,
      "name": "Bmongo",
      "age": 18,
      "iat": 1588139323,
      "exp": 1588139333
    }
    複製代碼

    注意:因爲JWT是默認不加密的,因此在這邊不要存敏感信息

  • verify signature

    這部分是對前兩部分的簽名,防止數據的篡改

    secret是服務器端保存的密鑰,只有服務器端知道,再使用header中所指定的簽名算法對上面的倆部分進行簽名,按照如下公式生成簽名

    HMACSHA256(
        base64UrlEncode(header) + "." +
        base64UrlEncode(payload),
        secret
    )
    複製代碼

    算出簽名以後,把三部分經過.分隔開返回給用戶就好了

    JWT例子:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTAsIm5hbWUiOiLlvKDkuIkiLCJhZ2UiOjE2LCJpYXQiOjE1ODgxMzkzMjMsImV4cCI6MTU4ODEzOTMzM30.WzZp_aNgiw4iTsX7buxMhZe0z0e94Ve6ImEZ8L8L78c
    複製代碼
  • 客戶端請求

    每次客戶端的請求都須要帶上這個token,通常是把token寫入到請求的headers中

3、Node.js中使用

Node.js中使用JWT

1.開始使用

經過npm包jsonwebtoken來完成token的生成和驗證

npm install --save jsonwebtoken
複製代碼
2.生成、驗證Token
const jwt = require("jsonwebtoken")
//撒鹽,加密時候混淆
const secret = '113Bmongojsdalkfnxcvmas'

//生成token
//info也就是payload是須要存入token的信息
function createToken(info) {
	let token = jwt.sign(info, secret, {
        //Token有效時間 單位s
		expiresIn:60 * 60 * 10
	})
	return token
}

//驗證Token
function verifyToken(token) {
	return new Promise((resolve, reject) => {
		jwt.verify(token, secret, (error, result) => {
            if(error){
                reject(error)
            } else {
                resolve(result)
            }
		})
	})
}
複製代碼
3.使用
const express = require("express")
const app = express()
const jwt = require("jsonwebtoken")
//撒鹽,加密時候混淆
const secret = '113Bmongojsdalkfnxcvmas'
const user = {
	id:10,
	name:"Bmongo",
	age:16,
}

//生成token
//info也就是payload是須要存入token的信息
function createToken(info) {
	let token = jwt.sign(info, secret, {
        //Token有效時間 單位s
		expiresIn:60 * 60 * 10
	})
	return token
}

//驗證Token
function verifyToken(token) {
	return new Promise((resolve, reject) => {
		jwt.verify(token, secret, (error, result) => {
            if(error){
                reject(error)
            } else {
                resolve(result)
            }
		})
	})
}

//設置容許跨域
app.use(function(req, res, next) {
    //指定容許其餘域名訪問 *全部
	res.setHeader("Access-Control-Allow-Origin", "*");
    //容許客戶端請求頭中帶有的
	res.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
    //容許請求的類型
	res.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
	res.setHeader("X-Powered-By",' 3.2.1')
    //讓options請求快速返回
	if(req.method=="OPTIONS") res.send(200);
	else  next();
});

//白名單
const whiteList = ['/login']

app.use((req,res,next) => {
	if(!whiteList.includes(req.url)) {
		verifyToken(req.headers.authorization).then(res => {
			next()
		}).catch(e => {
			res.status(401).send('invalid token')
		})
	} else {
		next()
	}
})

app.post('/login',(req,res) => {
	let token = createToken(user)
	res.json({token})
})

app.get("/api/info", (req,res) => {
	res.send({
		result:1,
		data:{
            "name":"Bmongo",
            "id":1
        }
	})
})
複製代碼
相關文章
相關標籤/搜索