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

前言

接着上遍文章(使用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 一样了么?)。

总结

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

(0)

相关推荐

  • express + jwt + postMan验证实现持久化登录

    原理 第一次登陆时会返回一个经过加密的token,下一次访问接口(携带登录返回你的token)的时候,会对token进行解密,如果解密正在进行,说明你已经登录,再把过期时间延长 下载 npm init -y // 一键初始化 npm install express -s // 下载express npm install cors // 跨域中间件 npm install body-parser // body-parser中间件 解析带请求体的数据(post,put) npm install j

  • vue+express+jwt持久化登录的方法

    jwt 持久化验证前端篇,node 配置详情请移步这里 我用的是vue3,下面是 src 的目录 用到的依赖 验证思路 Home 页写登录,然后在 About 页获取到登录名. 登录成功缓存 token,进入About页时,通过判断是否有 token 来判断是否登录/登录超时 登录页 在登录页输入用户名和密码,将其提交到vuex // src/views/Home.vue <template> <div class="home"> <input type=

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

    前言 接着上遍文章(使用session保存用户数据)来让使用jwt保存用户数据. 这里会用到passport-jwt/jsonwebtoken. passport-jwt是passport的一个验证策略.它使用jwt(json web token)验证. jsonwebtoken是一个编码.解码.验证jwt的模块. 使用jwt保存用户数据与使用session保存用户数据对比 session json web token 保存在server 保存在client 因session保存在server,

  • ThinkPHP5框架中使用JWT的方法示例

    本文实例讲述了ThinkPHP5框架中使用JWT的方法.分享给大家供大家参考,具体如下: JWT下载地址:https://jwt.io 可以直接去github上下载,也可以使用composer 使用composer的话要确保你的电脑上安装了composer,进入项目根目录下载即了,自动会放在vendor目录下 创建文件 我是放在common目录下 使用教程 github都有的 贴源码 JWTAuth.php <?php namespace app\common\Auth; use \Lcobuc

  • gin框架中使用JWT的定义需求及解析

    目录 什么是JWT? 为什么需要JWT? 生成JWT和解析JWT 定义需求 生成JWT 解析JWT 在gin框架中使用JWT 什么是JWT? JWT全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token实现方式,目前多用于前后端分离项目和OAuth3.0业务场景下. 为什么需要JWT? 在之前的一些web项目中,我们通常使用的是Cookie-Session模式实现用户认证.相关流程大致如下: 用户在浏览器端填写用户名和密码,并发送给服务端 服务端对用户

  • Yii框架中jquery表单验证插件用法示例

    本文实例讲述了Yii框架中jquery表单验证插件用法.分享给大家供大家参考,具体如下: 运行效果图如下: 视图层: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtm

  • Django中的JWT身份验证的实现

    1.认证与授权 1.验证:身份验证是验证个人或设备标识的过程.身份验证过程之一是登录过程.注册网站后,您的信息(ID,密码,名称,电子邮件等)将存储在其数据库中.之后,您无需创建帐户即可提供信息.相反,您只需要提供用户名和密码来验证您的身份,网站就会自动知道您正在访问. 2.授权:授权是用于确定用户特权或访问级别的安全机制.在许多社区网站上,只有上传帖子和管理员的人才能删除它.当其他人尝试删除帖子时,网站应该抛出错误(但是在许多情况下,他们甚至看不到删除按钮).因此,对于每个请求,用户都需要证明

  • thinkPHP框架中执行原生SQL语句的方法

    本文实例讲述了thinkPHP框架中执行原生SQL语句的方法.分享给大家供大家参考,具体如下: 怎样在thinkphp里面执行原生的sql语句? $Model = new Model();//或者 $Model = D(); 或者 $Model = M(); $sql = "select * from `order`"; $voList = $Model->query($sql); 只是需要new一个空的模型继承Model中的方法. 注意query是查功能,execute是增删改

  • php中使用base HTTP验证的方法

    本文实例讲述了php中使用base HTTP验证的方法.分享给大家供大家参考.具体如下: function http_auth($un, $pw, $realm = "Secured Area") { if(!(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW']) && $_SERVER['PHP_AUTH_USER'] == $un && $_SERVER[

  • layui框架中layer父子页面交互的方法分析

    本文实例讲述了layui框架中layer父子页面交互的方法.分享给大家供大家参考,具体如下: layer是一款近年来备受青睐的web弹层组件,官网地址是:http://layer.layui.com/ 可以从官网上下载最新版本. 还可点击此处本站下载. 当layer以iframe层的方式弹出新的窗口(子页面),如何在子页面中访问父页面的元素和函数. 1.访问父页面元素值 var parentId=parent.$("#id").val();//访问父页面元素值 2.访问父页面方法 va

  • ThinkPHP框架中使用Memcached缓存数据的方法

    本文实例讲述了ThinkPHP框架中使用Memcached缓存数据的方法.分享给大家供大家参考,具体如下: ThinkPHP默认使用文件缓存数据,支持Memcache等其他缓存方式,有两个PHP扩展:Memcache和Memcached,Memcahe官方有说明,主要说一下Memcached. 相对于PHP Memcache,php Memcached是基于原生的c的libmemcached的扩展,更加完善,建议替换为php memcached. 版本3.2.2开始内置了Memcached驱动(

  • laravel框架中控制器的创建和使用方法分析

    本文实例讲述了laravel框架中控制器的创建和使用方法.分享给大家供大家参考,具体如下: laravel中我们可以使用 artisan 命令来帮助我们创建控制器文件. php artisan make:controller TestController TestController 控制器名我们可以任意指定.文件默认会创建在 app\Http\Controllers 目录下. 打开控制器文件,我们就可以添加自已的方法了. <?php namespace App\Http\Controllers

随机推荐