Node express项目(1)JWT验证

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,用于解决连接池的回调抛出,大家有啥不懂的可以评论下提出喔~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值