在Express中使用JWT的操作与报错问题

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 在Express中使用JWT的操作与报错问题

安装JWT相关的包

运行如下命令,安装如下两个JWT相关的包:

npm install jsonwebtoken express-jwt

其中:

  • jsonwebtoken 用于生成JWT字符串
  • express-jwt 用于将JWT字符串解析还原成JSON对象

导入JWT相关的包

使用 require() 函数,分别导入JWT相关的两个包:

//导入用于生成JWT字符串的包
const jwt = require('jsonwebtoken');
//导入用于将客户端发送过来的JWT字符串解析还原成JSON对象的包
const expressJWT = require('express-jwt');

定义secret密钥

为了保证JWT字符串的安全性,防止JWT字符串在网络传输过程中被人破解,需要定义一个用于加密和解密的secret密钥:

  1. 当生成JWT字符串的时候,需要使用secret密钥对用户的信息进行加密,最终得到加密好的JWT字符串
  2. 当把JWT字符串解析还原成JSON对象的时候,需要使用secret密钥进行解密
//secret 密钥的本质: 一个字符串
const secretKey = 'secretkey!!!'

在登录成功后生成JWT字符串

调用jsonwebtoken包提供的 sign() 方法,将用户的信息加密成JWT字符串,响应给客户端:

app.post('/api/login', (req, res) => {
    //将 req.body 请求体中的数据 转存为 userinfo 常量
    const userinfo = req.body;
    //登录失败
    if (userinfo.username !== 'admin' || userinfo.password !== '000000') {
        return res.send({
            status: 400,
            msg: '登录失败!'
        })
    }
    //登录成功
    //在登录成功之后 调用 jwt.sign() 方法生成JWT字符串 并通过 token 属性发送给客户端
    //参数1: 用户的信息对象
    //参数2: 加密的密钥
    //参数3: 配置对象 可以配置当前 token 的有效期
    const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' });
    res.send({
        status: 200,
        msg: '登录成功',
        token: 'tokenStr' //要发送给客户端的token字符串
    })
})

将JWT字符串还原为JSON对象

客户端每次在访问那些有权限接口的时候,都要主动通过请求头中的 Authorization 字段,将 Token 字符串发送到服务器进行身份认证

此时,服务器可以通过 express-jwt 这个中间件,自动将客户端发送过来的 Token 解析还原成 JSON 对象

//使用 app.use() 注册将JWT字符串解析还原成JSON对象的中间件
//.unless() 方法通过正则表达式 指定哪些接口不需要通过权限
//正则中 '\'用来转义 '^'表示指定以什么开头的字符串
app.use(expressJWT({ secret: secretKey }).unless({path: [/^\/api\//]}));
//如果出现报错 尝试在 secret: secretKey的后面加上 ", algorithms: ['HS256'] "

使用req.user获取用户信息

express-jwt 这个中间件配置成功之后,即可在那些有权限的接口中,使用 req.user 对象,来访问从 JWT 字符串中解析出来的用户信息了,示例代码如下:

//有权限的接口
app.get('/admin/getinfo', (req, res) => {
    //使用 req.user 获取用户信息 并使用data属性将用户信息发送给客户端
    console.log(req.user);
    res.send({
        status: 200,
        message: '获取用户信息成功!',
        data: req.user //要发送给客户端的信息
    })
})

先登录一次,获取token

再在指定的时间内,进行getinfo,需要将登录时得到的token,通过Header传给接口验证

捕获解析JWT失败后产生的错误

当使用express-jwt解析Token字符串时,如果客户端发送的Token字符串过期不合法,会产生一个解析失败的错误,影响项目的正常运行,可以通过Express的错误中间件,捕获这个错误并且进行相关的处理,示例代码如下:

//在所有路由后面定义错误中间件
//使用全局错误处理中间件 捕获解析 JWT 失败后产生的错误
app.use((err, req, res, next) => {
    //判断是否由 Token 解析失败导致的
    if (err.name == 'UnauthorizedError') {
        return res.send({
            status: 401,
            message: '无效的Token'
        })
    }
    res.send({
        status: 500,
        message: '未知的错误'
    })
})

老版本express-jwt @6 和新版本express-jwt @8

老版本express-jwt用法:

const expressJWT = require("express-jwt")
const scretKey = 'hhhhhhh'
app.use(expressJWT({
  secret: scretKey,
  algorithms:["HS256"],
}).unless({
  // 列表里的路由不会被token限制访问
  path:["/login",{url : /^\/upload/ , methods : ["GET"]}]
}));

新版本express-jwt用法:

const expressJWT = require("express-jwt")
app.use(expressJWT.expressjwt({
  secret: scretKey,
  algorithms:["HS256"],
}).unless({
  // 列表里的路由不会被token限制访问
  path:["/login",{url : /^\/upload/ , methods : ["GET"]}]
}));

其中algorithms是配置算法,值有多种

  1. HS256 使用同一个「secret_key」进行签名与验证(对称加密)。一旦 secret_key 泄漏,就毫无安全性可言了。
  • 因此 HS256 只适合集中式认证,签名和验证都必须由可信方进行。
  • 传统的单体应用广泛使用这种算法,但是请不要在任何分布式的架构中使用它!

RS256 是使用 RSA 私钥进行签名,使用 RSA 公钥进行验证。公钥即使泄漏也毫无影响,只要确保私钥安全就行。

  • RS256 可以将验证委托给其他应用,只要将公钥给他们就行。
  1. ES256RS256 一样,都使用私钥签名,公钥验证。算法速度上差距也不大,但是它的签名长度相对短很多(省流量),并且算法强度和 RS256 差不多
相关文章
|
JavaScript
Express+Vue2+Element-ui上传图片操作
Express+Vue2+Element-ui上传图片操作
127 0
|
6月前
|
消息中间件 Serverless Go
Serverless 应用引擎操作报错合集之通过自定义域名配置jwt认证,始终报错:"Code": "JWTTokenIsInvalid",是什么导致的
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
120 2
|
7月前
使用JWT的服务分布式部署之后报错:JWT Check Failure:
使用JWT的服务分布式部署之后报错:JWT Check Failure:
118 1
|
前端开发 中间件
node express前端 canvas操作图片 报跨域
我后台使用的是 node + express ,所以首先定位问题所在,图片是属于静态资源的,然后我们后台解析静态资源使用 express 里面的 static 中间件。所以打开对应的文档,查看对应的配置。
node express前端 canvas操作图片 报跨域
Springboot JWT 报错 Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
Springboot JWT 报错 Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
484 0
|
PHP
【laravel】JWT过期报错Route [login] not defined.
【laravel】JWT过期报错Route [login] not defined.
278 0
【laravel】JWT过期报错Route [login] not defined.
|
SQL 存储 前端开发
【NodeJS】归纳篇(三)Express | 链式操作 | cookie && session | 模板引擎 | Router | mysql
【NodeJS】归纳篇(三)Express | 链式操作 | cookie && session | 模板引擎 | Router | mysql
185 0
|
前端开发 NoSQL JavaScript
前端培训-中级阶段(52)- Express安装,使用 Express完成RESTful操作 MongoDB
前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。 当我们需要起一个服务器时,我猜大多数人的选择是 Express (至少我看到的一些小工具是)。 今天我们来安装一下,然后结合上节课操作一下 MongoDB 。
153 0
|
SQL Oracle 关系型数据库