1、安装依赖
pnpm i express-jwt // 解析jwt
pnpm i jsonwebtoken // 用于生成和解析token
pnpm i mysql
pnpm i express
pnpm i router
2、逻辑分析及功能代码
总共我们需要这五个文件,下面我依次介绍这五个地方
首先一般数据库肯定需要连接池,那你肯定要对这部分做下处理
// pool.js
const mysql = require('mysql')
const util = require('./utils')
const pool = mysql.createPool({
host: 'localhost', //数据库地址
user: 'root', //用户
password: 'xxx', //密码
database: 'xxx', //库名
port: 3306
})
let query = async (sql, values ) => {
// to 函数是处理promise中返回格式的方法
// 返回一个 Promise
let poolPromise = await util.to(new Promise(( resolve, reject ) => {
pool.getConnection(function(err, connection) {
if (err) {
reject( err )
} else {
connection.query(sql, values, ( err, rows) => {
if ( err ) {
reject( err )
} else {
resolve( rows )
}
// 结束会话
connection.release()
})
}
})
}))
return poolPromise
}
module.exports = query
其次是我们的通用方法存放的地方
1、setToken :用来对数据进行加密的方法,返回值为token
2、verToken: 验证解析token的合理性
3、to: promise的格式处理返回
// utils.js
const query = require('./pool')
//用于生成和解析token
let jwt = require('jsonwebtoken');
let signkey = 'lin_da_da_yo';
/**
* 查找一个帐号
*/
const findOne = async function (user) {
[err, data] = await query(`SELECT * FROM login WHERE account = '${user.account}'`)
if (err) {
throw new Error(err)
} else {
return data
}
}
exports.findOne = findOne
exports.setToken = function(username,password){
return new Promise((resolve,reject)=>{
const token = jwt.sign({
name:username,
_id:password
},signkey,{ expiresIn:'1h' });
resolve(token);
})
}
exports.verToken = function(token){
return new Promise((resolve,reject)=>{
var info = jwt.verify(token.split(' ')[1],signkey);
resolve(info);
})
}
exports.to = function(promise, errorProps = {}, errorFirst = true) {
return promise.then((data) => {
return errorFirst ? [null, data] : [data, null]
})
.catch(err => {
if(errorProps) Object.assign(err, errorProps)
errorFirst ? [err, undefined] : [undefined, err]
})
}
下面是请求的拦截及验证,如果你了解过axios,那么下面的逻辑就和axios拦截器类似
// connect.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const vertoken = require('./utils')
const expressJwt = require('express-jwt');
app.all("*", function(req, res, next) {
//设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin", "*");
//允许的header类型
res.header("Access-Control-Allow-Headers", "content-type,Authorization");
//跨域允许的请求方式
res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
res.header("Content-Type", "application/json;charset=utf-8");
if (req.method.toLowerCase() == 'options')
res.send(200); //让options尝试请求快速结束
else
next();
})
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// 解析token获取用户信息
app.use(function(req, res, next) {
var token = req.headers['Authorization'];
if(token == undefined){
return next();
}else{
vertoken.verToken(token).then((data)=> {
req.data = data;
return next();
}).catch((error)=>{
return next();
})
}
});
//验证token是否过期并规定哪些路由不用验证
app.use(expressJwt({
secret: 'lin_da_da_yo',
algorithms: ['HS256']
}).unless({
path: ['/map/login']//除了这个地址,其他的URL都需要验证
}));
//当token失效返回提示信息
app.use(function(err, req, res, next) {
if (err.status == 401) {
return res.status(401).send({
code: 0,
msg: 'token失效'
});
}
});
exports.app = app
然后就是我们node项目的主文件,这里就是路由的模式,如果你写过vue或java等,应该是很熟悉这写法的
const { app } = require('./connect');
var map = require('./router/map')
app.use('/map', map)
app.listen(8001);
3、业务代码(登录)
// /router/map.js
var express = require('express')
var router = express.Router()
const user = require('../utils')
const query = require('../pool')
//POST 登录
router.post('/login', (req, res) => {
user.findOne(req.body) // 这一步,我是在sql中查找有无当前登录账号的用户
.then(data => {
return data
})
.then(data => {
if (data.length > 0) {
if (data[0].password == req.body.password) {
return data[0]
} else {
throw new Error('登录失败,请检查密码是否正确')
}
} else {
throw new Error('登录失败,请检查账号是否正确')
}
})
// 获取动态路由菜单
.then(async data => {
const [err, rows] = await query(`SELECT * FROM 你的菜单表`)
if (err) {
throw new Error(err)
} else {
return {
...data,
menu: rows
}
}
})
.then(data => {
// 注入token
user.setToken(data.account,data.password).then((token)=>{
return res.send({ code: 2000, data: {
...data,
token: token
}})
})
})
.catch(e => {
res.send({
code: 0,
msg: e.message
})
})
})
4、项目注意点
4.1、express-jwt 依赖默认安装6.0.0后版本,需要在expressJwt实例化时多添加一个参数:algorithms: ['HS256']
4.2、本项目其实相对比较完善,里面也多用的是promise和async,await,用于解决连接池的回调抛出,大家有啥不懂的可以评论下提出喔~