基于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‘