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 相关文章推荐
一个简单的网站访问JS计数器 刷新1次加1次访问
Sep 20 Javascript
jquery中prop()方法和attr()方法的区别浅析
Sep 06 Javascript
js控制页面控件隐藏显示的两种方法介绍
Oct 09 Javascript
JavaScript中使用document.write向页面输出内容实例
Oct 16 Javascript
基于jquery实现发送文章到手机的代码
Dec 26 Javascript
JS与jQ读取xml文件的方法
Dec 08 Javascript
JS遍历ul下的li点击弹出li的索引的实现方法
Sep 19 Javascript
Node.js环境下Koa2添加travis ci持续集成工具的方法
Jun 19 Javascript
Vue2.0基于vue-cli+webpack父子组件通信(实例讲解)
Sep 14 Javascript
vue+iview+less 实现换肤功能
Aug 17 Javascript
vue 使用vue-i18n做全局中英文切换的方法
Oct 29 Javascript
Vue项目打包压缩的实现(让页面更快响应)
Mar 10 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安全防范技巧分享
2011/11/03 PHP
深入浅析PHP无限极分类的案例教程
2016/05/09 PHP
PHP实现获取第一个中文首字母并进行排序的方法
2017/05/09 PHP
PHP实现爬虫爬取图片代码实例
2021/03/03 PHP
js 父窗口控制子窗口的行为-打开,关闭,重定位,回复
2010/04/20 Javascript
JavaScript 实现类的多种方法实例
2013/05/01 Javascript
jquery遍历筛选数组的几种方法和遍历解析json对象
2013/12/13 Javascript
jquery自动填充勾选框即把勾选框打上true
2014/03/24 Javascript
通过JS判断联网类型和连接状态的实现代码
2015/04/01 Javascript
简介JavaScript中的italics()方法的使用
2015/06/08 Javascript
JS模拟的Map类实现方法
2016/06/17 Javascript
AngularJS 2.0入门权威指南
2016/10/08 Javascript
关于微信上网页图片点击全屏放大效果
2016/12/19 Javascript
vue单页应用中如何使用jquery的方法示例
2017/07/27 jQuery
Bootstrap Table快速完美搭建后台管理系统
2017/09/20 Javascript
vue.js vue-router如何实现无效路由(404)的友好提示
2017/12/20 Javascript
JS实现打砖块游戏
2020/02/14 Javascript
一个小示例告诉你Python语言的优雅之处
2014/07/04 Python
Python 实现数据结构中的的栈队列
2019/05/16 Python
Python3 实现爬取网站下所有URL方式
2020/01/16 Python
python递归函数用法详解
2020/10/26 Python
python中用ctypes模拟点击的实例讲解
2020/11/26 Python
解锁canvas导出图片跨域的N种姿势小结
2019/01/24 HTML / CSS
受外贸欢迎的美国主机:BlueHost
2017/05/16 全球购物
信息科学与技术专业求职信范文
2014/02/20 职场文书
大学教师师德师风演讲稿
2014/08/22 职场文书
观看《周恩来的四个昼夜》思想汇报
2014/09/12 职场文书
群众路线个人剖析材料
2014/10/07 职场文书
老龙头导游词
2015/02/11 职场文书
大学班干部竞选稿
2015/11/20 职场文书
2016秋季幼儿园开学寄语
2015/12/03 职场文书
2016年教师节贺卡寄语
2015/12/04 职场文书
演讲开头怎么书写?
2019/08/06 职场文书
Python中相见恨晚的技巧
2021/04/13 Python
Python OpenCV 图像平移的实现示例
2021/06/04 Python
win10蓝屏0xc0000001安全模式进不了怎么办?win10出现0xc0000001的解决方法
2022/08/05 数码科技