express框架中使用JWT

  1. 安装JWT相关的包:
    • jsonwebtoken: 用于生成 JWT 字符串
    • express-jwt 用于将 JWT 字符串解析还原成 JSON 对象
npm i jsonwebtoken express-jwt
  1. 导入JWT相关包
const express = require('express')//express框架
const jwt = require('jsonwebtoken')//jwt生成器
const expressJWT = require('express-jwt')//jwt解析器
// const { expressJWT:expressJWT } = require("express-jwt")//高版本使用 jwt解析器
  1. 设置密钥和使用jwt.sign()加密你想加密的信息生成jwt字符串
    • 为了保证 JWT 字符串的安全性,防止 JWT 字符串在网络传输过程中被别人破解,我们需要专门定义一个用于加密和解密的 secret 密钥:
      • 当生成 JWT 字符串的时候,需要使用 secret 密钥对用户的信息进行加密,最终得到加密好的 JWT 字符串
      • 当把 JWT 字符串解析还原成 JSON 对象的时候,需要使用 secret 密钥进行解密
// 设置token密钥
const secretKey = 'miyao'

//调用 jsonwebtoken 包提供的 sign() 方法,将用户的信息加密成 JWT 字符串,响应给客户端:
//jwt.sign() 方法生成 JWT 字符串。
// 参数1:用户的信息对象
// 参数2:加密的秘钥
// 参数3:配置对象,可以配置当前 token 的有效期
// 记住:千万不要把密码加密到 token 字符中
const tokenStr = jwt.sign(
{username:req.body.username},//将用户名加密发送给客户端
secretKey,//加密密钥
{ expiresIn: '30h' }//token有效时间 30小时
)
res.send({//登陆成功发送token
status: 200,
message: '登录成功!',
token: tokenStr, // 要发送给客户端的 token 字符串
})
  1. 注册解密器
    • 解密器注册成功后,我们在调用需要鉴权的接口时可以通过req.user来获取我们解密出来的信息
    • 客户端每次在访问那些有权限接口的时候,都需要主动通过请求头中的 Authorization 字段,将 Token 字符串发送到服务器进行身份认证。
    • 此时,服务器可以通过express-jwt这个中间件,自动将客户端发送过来的 Token 解析还原成 JSON 对象:
// 注册token解密器
// 注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上
// 里面传入的对象:密钥(加密解密都是一个),unless表示里面的带指定路径的不需要token鉴权
app.use(expressJWT(
{ //按着模板填即可
secret: secretKey ,//密钥
algorithms: ["HS256"],//设置jwt算法
}
).unless({ path: [/^\/api\//] }))//表示携带/api的接口不需要token鉴权
  1. 注册解密器(新版)
  • 在新版的jwt模块当中,解密token不再这么复杂, 提供了一个新的api接口来解密token
    //jwt.verify()函数
    const paylod = jwt.verify(token , '密钥')
    //输出的 paylod 就能token解密后的数据
  1. 创建一个错误中间件,捕获解析 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: '未知的错误',
})
})

完整的代码展示

  • 服务端(app.js)
// jwt身份认证

// 引入相应的包
const express = require('express')//express框架
const jwt = require('jsonwebtoken')//jwt生成器
const expressJWT = require('express-jwt')//jwt解析器
// const { expressJWT:expressJWT } = require("express-jwt")//高版本使用 jwt解析器

// 创建服务器
const app = express()

// 配置解析post参数的两个内置中间件
// 通过express.json()这个中间件,解析表单中的JSON格式的数据
app.use(express.json())//解析post的请求题参数(json格式)
// 通过express.urlencoded()这个中间件,来解析表单中的url-encoded格式的数据
app.use(express.urlencoded({extended:false}))//解析post的请求题参数(encoded格式)

// 学习重点1: 设置token密钥
const secretKey = 'miyao'

// 学习重点3 : 注册token解密器
// 注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上
// 里面传入的对象:密钥(加密解密都是一个),unless表示里面的带指定路径的不需要token鉴权
app.use(expressJWT(
{ //按着模板填即可
secret: secretKey ,//密钥
algorithms: ["HS256"],//设置jwt算法
}
).unless({ path: [/^\/api\//] }))//表示携带/api的接口不需要token鉴权


// 设置登录接口
app.post('/api/login' , (req , res)=>{
console.log(req.body);
// 判断用户提交的登录信息是否正确
if (req.body.username !== 'lam' || req.body.password !== '123') {
return res.send({ status: 400, msg: '登录失败' })
}

// 登陆成功(启动jwt加密,将用户信息通过密钥加密生成token发送给浏览器)
/*
学习重点2 : 在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。
并通过 token 属性发送给客户端
*/
// 参数1:用户的信息对象
// 参数2:加密的秘钥
// 参数3:配置对象,可以配置当前 token 的有效期
// 记住:千万不要把密码加密到 token 字符中
const tokenStr = jwt.sign(
{username:req.body.username},//将用户名加密发送给客户端
secretKey,//加密密钥
{ expiresIn: '30h' }//token有效时间 30小时
)
res.send({
status: 200,
message: '登录成功!',
token: tokenStr, // 要发送给客户端的 token 字符串
})
})

// 这是一个有权限的 API 接口(需要token鉴权)
app.get('/admin/getinfo', function (req, res) {
// 学习重点4:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
console.log(req.user)
res.send({
status: 200,
message: '获取用户信息成功!',
data: req.user, // 要发送给客户端的用户信息
})
})

// 重点学习5 : 设置一个错误中间件 , 捕获解析 JWT 失败后产生的错误
app.use((err, req, res, next) => {
// 这次错误是由 token 解析失败导致的
if (err.name === 'UnauthorizedError') {//固定写法
return res.send({
status: 401,
message: '无效的token',
})
}
res.send({
status: 500,
message: '未知的错误',
})
})

// 启动服务器
app.listen(3000,()=>{
console.log('服务器已启动,3000端口正在监听...');
})

结果展示

  • 生成token
    image

  • 解析token并输出解析后的结果
    image
    image

  • 发生错误时(token过期或者token输入错误),错误中间件的捕获错误作用
    image