基於Node.js的token驗證
基於Node.js的token驗證
一、伺服器端
1. 目錄結構
2. 實現步驟
-
下載
Win64OpenSSL_Light-1_1_1c
生成公鑰和私鑰,在將公鑰和私鑰放入pem
資料夾中將openssl的安裝路徑新增到系統環境變數中:C:\Program Files\OpenSSL-Win64\bin
生成私鑰: openssl genrsa -out rsa_private_key.pem 1024
用私鑰生成公鑰:openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem可選:
對私鑰進行pkcs8編碼:openssl pkcs8 -in rsa_private_key.pem -topk8 -out pkcs9_rsa_private_key.pem -inform PEM -outform PEM -nocrypt
生成加密的私鑰:openssl genrsa -aes256 -passout pass:123456 -out aes_rsa_private_key.pem 1024
通過加密私鑰生成公鑰:openssl rsa -in aes_rsa_private_key.pem -passin pass:123456 -pubout -out rsa_public_key.pem -
建立
jwt.js
模組,寫入生成token
和驗證token
的方法/* 一、引入模組依賴 */ const fs = require('fs'); const path = require('path'); const jwt = require('jsonwebtoken'); /* 二、生成token */ function generateToken(data) { let created = Math.floor(Date.now() / 1000); // 建立token生成的時間(s) let cert = fs.readFileSync(path.join(__dirname, './pem/rsa_private_key.pem')); //私鑰 可以自己生成 let token = jwt.sign({ data, exp: created + 60 * 60, // 生成後1小時失效 }, cert, { algorithm: 'RS256' }); return token; } /* 三、校驗token */ function verifyToken(token) { let cert = fs.readFileSync(path.join(__dirname, './pem/rsa_public_key.pem')); //公鑰 可以自己生成 let res; try { if (token !== undefined) { let result = jwt.verify(token, cert, { algorithms: ['RS256'] }) || {}; res = result.data || {}; } } catch (e) { res = e; } return res; } /* 匯出生成和校驗token的方法 */ module.exports = { generateToken, verifyToken };
-
在登入的路由中生成
token
res.send({ code: 1, token: jwt.generateToken(result[0]) });
即利用
jwt.js
中生成token
的方法生成字串並返回給客戶端 -
建立中介軟體,攔截特定的url進行
token
驗證app.use((req, res, next) => { if (req.url != '/user/login' && (req.url.startsWith("/user") || req.url.startsWith("/orders"))) { let token = req.headers.token; let result = jwt.verifyToken(token); // 如果考驗通過就next,否則就返回登陸資訊不正確 if (result === undefined) { res.send({ status: 403, msg: "未提供證書" }) } else if (result.name == 'TokenExpiredError') { res.send({ status: 403, msg: '登入超時,請重新登入' }); } else if (result.name == "JsonWebTokenError") { res.send({ status: 403, msg: '證書出錯' }) } else { req.user = result; next(); } } else { next(); } });
二、瀏覽器端(vue)
-
對
axios
模組做一些初始化;客戶端傳送請求時,為請求加上token
字串,並使得post可以物件的方式傳遞引數;客戶端收到響應後,根據伺服器返回的token的狀態,對storage
裡的token
進行增刪操作,並設定vuex中的相關變數。import axios from "axios"; import qs from "qs"; import store from './store' const Axios = axios.create({ baseURL: "http://localhost:5050/", withCredentials: true }) Axios.interceptors.request.use( config => { // console.log("進入請求攔截器..."); //this.axios.post( //"user/signin", //{uname:dingding , upwd:123456} //) if (config.method === "post") { config.data = qs.stringify(config.data) // post('/', {請求的引數}),將post中req物件轉為字串(即傳送post請求時,可以使用物件) } if (localStorage.getItem("token")) { config.headers.token = localStorage.getItem("token"); } if (sessionStorage.getItem("token")) { config.headers.token = sessionStorage.getItem("token"); } return config; }, error => { console.log("===傳送請求攔截器報錯===") console.log(error); console.log("===end==="); Promise.reject(error); } ); Axios.interceptors.response.use( res => { // console.log("觸發響應攔截器...") if (res.data.status == 403) { localStorage.removeItem("token"); sessionStorage.removeItem("token"); store.commit("setIslogin", false); store.commit("setUname", ""); } else if (res.data.code == -1) { store.commit("setIslogin", false); store.commit("setUname", ""); //alert(res.data.msg+" 請先登入 !"); } else if (res.data.token) { store.commit("setUname", res.data.uname); store.commit("setIslogin", true); if (res.remember === "true") { localStorage.setItem("token", res.data.token); } else { sessionStorage.setItem("token", res.data.token); } } return res; }, error => { } ) export default { install: function(Vue, Option) { Vue.prototype.axios = Axios; } }
-
將初始化後的
axios.js
模組匯入main.js
中import axios from './axios'