1.服务器端安装jsonwebtoken
2.服务器端使用OpenSSL,安装OpenSSL(用来生成和使用私有秘钥和公有秘钥)
具体操作:
将openssl的安装路径添加到系统环境变量中:C:\Program Files\OpenSSL-Win64\bin
在对应的项目文件的node_modul文件夹下创建pem文件夹,在该路径下执行以下命令
生成私钥: 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
3.服务器端创建一个js模块(jwt.js)
代码:
// 引入模块依赖
const fs = require('fs');
const path = require('path');
const jwt = require('jsonwebtoken');
//生成token
function generateToken(data){
let created = Math.floor(Date.now() / 1000);
let cert = fs.readFileSync(path.join(__dirname, './pem/rsa_private_key.pem'));//私钥 可以自己生成
let token = jwt.sign({
data,
exp: created + 60 * 60,//设置过期时间一小时
}, 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;
}
module.exports = { generateToken, verifyToken };//导出这两个方法
4.服务器端通过中间件使用token:(且这个中间件在其他挂载路由器之前)
代码片段:
app.use((req, res, next)=>{
if (req.url != '/user/signin' && (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;//如果token对,一定会返回一个用户对象
next();
}
} else {
next();
}
});
其他接口可以直接使用req.user。而且登陆成功(所有与"我的"相关的接口)之后,还要res.send( { … , token: jwt.generateToken(result[0]) } )
5.客户端怎么发:
客户端的axios请求:
this.axios.get('cart',{
params: { },
headers: { token: localStorage.getItem('token') || sessionStorage.getItem('token') },
});
扩展:每个axios请求都要发送headers中的token,以及.then()中都要判断服务器返回过来的token,为了简便代码,可以添加拦截器;
①创建axios.js文件模块:
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)
}
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;
}
}
②main.js中引入:
import axios from './axios'
Vue.use(axios);