1. 程式人生 > 其它 >基於Node.js的token驗證

基於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'