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 相关文章推荐
Ajax+Json 级联菜单实现代码
Oct 27 Javascript
多浏览器兼容的获取元素和鼠标的位置的js代码
Dec 15 Javascript
jquery 快速回到页首的方法
Dec 05 Javascript
javascript 兼容各个浏览器的事件
Feb 04 Javascript
简单实现异步编程promise模式
Jul 31 Javascript
js密码强度检测
Jan 07 Javascript
JQuery点击行tr实现checkBox选中的简单实例
May 26 Javascript
javascript鼠标滑过显示二级菜单特效
Nov 18 Javascript
AngularJS实现与Java Web服务器交互操作示例【附demo源码下载】
Nov 02 Javascript
微信小程序的mpvue框架快速上手指南
May 15 Javascript
微信小程序自定义tabbar custom-tab-bar 6s出不来解决方案(cover-view不兼容)
Nov 01 Javascript
vue中实现高德定位功能
Dec 03 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
php socket实现的聊天室代码分享
2014/08/16 PHP
浅谈PHP面向对象之访问者模式+组合模式
2017/05/22 PHP
PHP PDO数据库操作预处理与注意事项
2019/03/16 PHP
jQuery去掉字符串起始和结尾的空格(多种方法实现)
2013/04/01 Javascript
js 时间函数应用加、减、比较、格式转换的示例代码
2013/08/23 Javascript
JS调试必备的5个debug技巧
2014/03/07 Javascript
JavaScript+CSS实现仿Mootools竖排弹性动画菜单效果
2015/10/14 Javascript
基于Jquery实现万圣节快乐特效
2015/11/01 Javascript
JavaScript+html5 canvas绘制缤纷多彩的三角形效果完整实例
2016/01/26 Javascript
jQuery使用正则表达式替换dom元素标签用法示例
2017/01/16 Javascript
jQuery弹出窗口简单实现代码
2017/03/09 Javascript
jquery实现tab选项卡切换效果(悬停、下方横线动画位移)
2017/05/05 jQuery
vue自动化表单实例分析
2018/05/06 Javascript
详解使用Next.js构建服务端渲染应用
2018/07/10 Javascript
详解nodejs 配置文件处理方案
2019/01/02 NodeJs
详解如何用webpack4从零开始构建react开发环境
2019/01/27 Javascript
layui 实现table翻页滚动条位置保持不变的例子
2019/09/05 Javascript
vue element upload组件 file-list的动态绑定实现
2019/10/11 Javascript
[01:04]DOTA2:伟大的Roshan雕塑震撼来临
2015/01/30 DOTA
python使用response.read()接收json数据的实例
2018/12/19 Python
Pytorch Tensor基本数学运算详解
2019/12/30 Python
使用Tensorflow将自己的数据分割成batch训练实例
2020/01/20 Python
django实现更改数据库某个字段以及字段段内数据
2020/03/31 Python
Pytho爬虫中Requests设置请求头Headers的方法
2020/09/22 Python
python使用matplotlib:subplot绘制多个子图的示例
2020/09/24 Python
HTML5文档结构标签
2017/04/21 HTML / CSS
Joe Fresh官网:加拿大时尚品牌和零售连锁店
2016/11/30 全球购物
新加坡领先的在线生活方式和杂货购物网站:EAMART
2019/04/02 全球购物
优秀大学生的自我评价
2014/01/16 职场文书
学生打架检讨书1000字
2014/01/16 职场文书
学校消防安全责任书
2014/07/23 职场文书
学校实习推荐信
2015/03/27 职场文书
电影小兵张嘎观后感
2015/06/03 职场文书
mysql在项目中怎么选事务隔离级别
2021/05/25 MySQL
深入理解python协程
2021/06/15 Python
MySQL对数据表已有表进行分区表的实现
2021/11/01 MySQL