express框架中使用jwt实现验证的方法


Posted in Javascript onAugust 25, 2019

前言

接着上遍文章(使用session保存用户数据)来让使用jwt保存用户数据。

这里会用到passport-jwt/jsonwebtoken。

passport-jwt是passport的一个验证策略。它使用jwt(json web token)验证。

jsonwebtoken是一个编码、解码、验证jwt的模块。

使用jwt保存用户数据与使用session保存用户数据对比

session json web token
保存在server 保存在client

因session保存在server,所以服务器压力比较大。听说并发量达到1k时就能看到效果。

因jwt保存在client,所以需要加密。

使用jwt

1. 安装依赖。

npm i passport-jwt jsonwebtoken

2. 创建一个配置文件,引用配置是使用。

// ./config.js
module.exports = {
 secretKey: '12345-67890-9876-54321',
 mongoUrl: 'mongodb://localhost:27017/confusion'
}

3. 使用数据库链接配置

var config = require('./config')
...
const url = config.mongoUrl
const connet = mongoose.connect(url, {useNewUrlParse: true, useCreateIndex: true})

4. 创建验证文件

./authenticate.js
var passport = require('passport'),
 LocalStrategy = require('passport-local').Strategy,
 User = require('./models/user')

var JwtStrategy = require('passport-jwt').Strategy,
 ExtractJwt = require('passport-jwt').ExtractJwt,
 jwt = require('jsonwebtoken')

var config = require('./config.js')

passport.use(new LocalStrategy(User.authenticate()))
passport.serializeUser(User.serializeUser())
passport.deserializeUser(User.deserializeUser())

exports.getToken = function (user) {
 return jwt.sign(user, config.secretKey, {expiresIn: 3600}) // 签发token时设置超时时间是3600s
}

var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken() // 从验证头中提取,模型默认是`'bearer'`.
opts.secretOrKey = config.secretKey

exports.jwtPassport = passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
 console.log('JWT payload: ', jwt_payload)
 User.findOne({_id: jwt_payload._id}, (err, user) => {
 if (err) {
 return done(err, false)
 } else {
 if (user) {
 return done(null, user)
 } else {
 return done(null, false)
 }
 }
 })
}))

exports.verifyUser = passport.authenticate('jwt', {session: false}) // 使用jwt就不再需要session保存用户数据了。

5. 用户申请登录时把jwt给前端

// routes/users.js
...
var authenticate = require('../authticate')
router.post('/login', passport.authenticate('local'), (req, res) => { // 登录时还是使用passport-local
 var token = authenticate.getToken({_id: req.user._id}) // 得到签发后的jwt
 res.statusCode = 200
 res.setHeader('Content-Type', 'application/json')
 res.json({success: true, token: token, status: 'You are successful logged in!'})
})

6. 前端保存token

// use localStorage
$.ajax({
 type: 'post',
 dataType: 'json',
 url: 'users/login',
 data: {
 username: 'un',
 password: 'pw'
 },
 success: funciton (res) {
 localStorage.token = getToken(res)
 },
 error: funciton (err) {...}
})
// 还可以使用vux方法。
// 还可以使用封装axios方法。

7. 用户登录超时
jsonwebtoken验证jwt后,若结果不通过,会有3种错误类型。分别是

TokenExpiredError // 当token超时时抛出。

err = {
 name: 'TokenExpiredError',
 massage: 'jwt expired',
 expired: [ExpDate]
}
JsonWebTokenError

jwt错误

err = {
 name: 'JsonWebTokenError',
 message: 'jwt malformed' // 'jwt malformed', 'jwt signature in required', 'invalid signature', 'jwt audience invalid. expected: [OPTIONS AUDIENCE]', 'jwt issuer invalid. expected: [OPTIONS ISSUER]', 'jwt id invalid. expected:[OPTIONS JWT ID]', 'jwt subject invalid. expected: [OPTIONS SUBJECT]'
}

NotBeforeError

当当前时间超过nbf的值时抛出该错误。

err = {
 name: 'NotBeforeError',
 message: 'jwt not active',
 date: 2018-10-04T16:10:44.000Z
}

passport在验证jwt不通过时(token过期也是一种不通过)自动向前端发送“状态码为401,内容是Unauthorized”.
在使用passport/passport-jwt/jsonwebtoken时没有发现处理token过期的方法。所以在使用passport-jwt验证不通过时再写一个验证是否过期的方法。

// authenicate.js
...
export.verifyUser = passport.authenticate('jwt', {
 session: false,
 failureRedirect: '/error/auth' // 在这个路由里统一处理验证不通过的事情
 })
// routes/error.js
...
router.get('/auth', (req, res, next) => {
 let header = req.headers
 let rawToken = header.authorization
 if (!rawToken.split(' ').length) {
 res.json({ // 统一的数据结构方便前端使用
 code: 403,
 data: {},
 message: 'error for get token'
 })
 } else {
 let token = rawToken.split(' ')[1]
 jwt.verify(token, config.secretKey, err => { // 这里用到jsonwebtoken/config。注意引用
 switch (err.name) {
 case 'TokenExpiredError':
 case 'NotBeforeError':
  let payload = jwt.decode(token)
  token = authenticate.getToken({_id: payload._id})
  res.statusCode = 200
  res.setHeader('Content-Type', 'application/json')
  res.json({success: true, token: token, status: '已经刷新token'})
  break
 case 'JsonWebTokenError':
 default:
  res.statusCode = 401
  res.json({
  code: 401,
  data: {
  error: err
  },
  message: 'token错误'
  })
  break
 }
 })
 }
 })

8. 用户jwt验证不通过

passport在验证jwt不通过时(token过期也是一种不通过)自动向前端发送“状态码为401,内容是Unauthorized”.

9. 用户申请登出

在前端删除token.

10. 不要打断活动用户的操作

在no.7里若因为token过期造成验证不通过,则向前端返回了新的token。不是在不影响用户操作前提下更新用户的token的。下面在的总结的几种不影响用户操作的前提下更新用户的token的方法。

  1. 前端设置一个定时器。在小于过期时间时向后端请求新token并保存起来。
  2. 把token放在cookie时。后端从cookie里取出token,在过期前更新token。
  3. 将 token 存入 DB(如 Redis)中,失效则删除;但增加了一个每次校验时候都要先从 DB 中查询 token 是否存在的步骤,而且违背了 JWT 的无状态原则(这不就和 session 一样了么?)。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
无语,javascript居然支持中文(unicode)编程!
Apr 12 Javascript
判断用户的在线状态 onbeforeunload事件
Mar 05 Javascript
javascript 学习笔记(六)浏览器类型及版本信息检测代码
Apr 08 Javascript
原生JS实现表单checkbook获取已选择的值
Jul 21 Javascript
JavaScript中的变量定义与储存介绍
Dec 31 Javascript
Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别
Dec 30 Javascript
vuex的module模块用法示例
Nov 12 Javascript
微信小程序实现打卡日历功能
Sep 21 Javascript
vue车牌号校验和银行校验实战
Jan 23 Javascript
微信小程序学习笔记之登录API与获取用户信息操作图文详解
Mar 29 Javascript
vue ssr服务端渲染(小白解惑)
Nov 10 Javascript
Vue 打包体积优化方案小结
May 20 Javascript
JS异步处理的进化史深入讲解
Aug 25 #Javascript
Vue源码分析之Vue实例初始化详解
Aug 25 #Javascript
javascript导出csv文件(excel)的方法示例
Aug 25 #Javascript
JavaScript在web自动化测试中的作用示例详解
Aug 25 #Javascript
angularjs自定义过滤器demo示例
Aug 24 #Javascript
Jquery实现获取子元素的方法分析
Aug 24 #jQuery
微信小程序class封装http代码实例
Aug 24 #Javascript
You might like
整理的9个实用的PHP库简介和下载
2010/11/09 PHP
php实现无限级分类实现代码(递归方法)
2011/01/01 PHP
SESSION信息保存在哪个文件目录下以及能够用来保存什么类型的数据
2012/06/17 PHP
LotusPhp笔记之:Cookie组件的使用详解
2013/05/06 PHP
PHP+MySQL使用mysql_num_rows实现模糊查询图书信息功能
2018/05/31 PHP
phpMyAdmin通过密码漏洞留后门文件
2018/11/20 PHP
基于ThinkPHP5框架使用QueryList爬取并存入mysql数据库操作示例
2019/05/25 PHP
jquery插件之信息弹出框showInfoDialog(成功/错误/警告/通知/背景遮罩)
2013/01/09 Javascript
js中的json对象详细介绍
2014/10/29 Javascript
30个经典的jQuery代码开发技巧
2014/12/15 Javascript
jquery html动态添加的元素绑定事件详解
2016/05/24 Javascript
Javascript 普通函数和构造函数的区别
2016/11/05 Javascript
Bootstrap table右键功能实现方法
2017/02/20 Javascript
React/Redux应用使用Async/Await的方法
2017/11/16 Javascript
jQuery Ajax实现Select多级关联动态绑定数据的实例代码
2018/10/26 jQuery
基于jquery实现的tab选项卡功能示例【附源码下载】
2019/06/10 jQuery
vue-cli在 history模式下的配置详解
2019/11/26 Javascript
在weex中愉快的使用scss的方法步骤
2020/01/02 Javascript
关于小程序优化的一些建议(小结)
2020/12/10 Javascript
wxpython 学习笔记 第一天
2009/03/16 Python
python的文件操作方法汇总
2017/11/10 Python
Python复制Word内容并使用格式设字体与大小实例代码
2018/01/22 Python
Python实现定时精度可调节的定时器
2018/04/15 Python
对python数据切割归并算法的实例讲解
2018/12/12 Python
详解Appium+Python之生成html测试报告
2019/01/04 Python
python实现列表中最大最小值输出的示例
2019/07/09 Python
python 直接赋值和copy的区别详解
2019/08/07 Python
关于numpy数组轴的使用详解
2019/12/05 Python
CSS实现圆形放大镜狙击镜效果 只有圆圈里的放大
2012/12/10 HTML / CSS
阿拉伯世界最大的电子卖场:Souq埃及
2016/08/01 全球购物
来自美国主售篮球鞋的零售商店:KICKSUSA
2017/11/28 全球购物
泰国第一在线超市:Tops
2021/02/13 全球购物
2014学雷锋活动总结
2014/03/09 职场文书
中国梦我的梦演讲稿
2014/04/23 职场文书
房屋租赁委托书范本
2014/10/04 职场文书
世界地球日活动总结
2015/02/09 职场文书