运行如下命令,安装如下两个JWT相关的包:
npm install jsonwebtoken express-jwt
其中:
// 1.导入用于生成JT字符串的包
const jwt = require('jsonwebtoken')//2.导入用于将客户端发送过来的JwT字符串,解析还原成JS0N对象的包
const { expressjwt: jwt } = require("express-jwt");
为了保证JWT字符串的安全性,防止JWT字符串在网络传输过程中被别人破解,我们需要专门定义一个用于加密和解密的secret密钥:
密钥可以是任意的字符串,越复杂越好
//3.secret密钥的本质:就是一个字符串
const secretKey = 'Nodejs No1 ^_^'
调用jsonwebtoken
包提供的sign()
方法,将用户的信息加密成JWT字符串,响应给客户端:
千万不要把密码加密到token中
//登录接口
app.post('/api/login', (req, res) => {// ··省略登录失败情况下的代码//用户登录成功之后,生成JWT字符串,通过token属性响应给客户端res.send({status: 200,message: '登录成功!',//调用jwt.sign()生成JWT字符串,三个参数分别是:用户信息对像、加密密钥、配置对橡token: jwt.sign({username: userinfo.username}, secretKey, {expiresIn: '30s'})})
})
完整代码:
const express = require("express")
const jwt = require("jsonwebtoken")
const {urlencoded} = require("express");const app = express()
app.use(urlencoded({extended: false}))const secretKey = "kkk *_*"app.get("/login", (req, res) => {if (req.body.username === 'admin' && req.body.password === 'admin') {const tokenStr = jwt.sign({username: req.body.username}, secretKey, {expiresIn: "24h"})res.send({status: 200,msg: 'success',token: tokenStr})} else {req.send({msg: "账号或者密码错误"})}})app.listen(80, () => {console.log("server start")
})
启动后通过接口测试,得到结果如下:
客户端海次在访问那些有权限接口的时候,都需要主动通过请求头中的Authorization字段,将Token字符串发送到服务器进行身份认证。
此时,服务器可以通过express-jwt
这个中间件,自动将客户端发送过来的Token解析还原成json对像:
express-jwt7版本之后用法发生了变化,参考express-jwt - npm
const { expressjwt } = require("express-jwt");// 使用app.use()来注册中间件
// .unless({path:[/^\/api\//]})用来指定哪些接口不需要访问权限
app.use(expressjwt({secret: secretKey,algorithms: ["HS256"]}).unless({path: [/^\/api\//]})
)
当express-jwt
这个中间件配置成功之后,即可在那些有权限的接口中,使用req.user
对象,来访问从JWT字符串中解析出来的用户信息了,示例代码如下:
只有配置好了
express-jwt
中间件之后才能通过req.user
获取用户信息,
//这是一个有权限的API接口
app.get('/admin/getinfo', (req, res) => {console.log(re.user)res.send({status: 200,message: '获取用户信息成功!',data: req.auth})
})
当使用express-jwt解析Token字符串时,如果客户端发送过来的Token字符串过期或不合法,会产生一个解析失败的错误,影响项目的正常运行。我们可以通过Express的错误中间件,捕获这个错误并进行相关的处理,示例代码如下:
记得放在最后
app.use((err, req, res, next) => {//token解析失败导致的错误if (err.name === 'UnauthorizedError') {return res.send({status: 401, message: '无效的token'})}//其它原因导致的错误res.send({status: 500, message: '未知错误'})
})
const express = require("express")
const jwt = require("jsonwebtoken")
const {urlencoded} = require("express");
const {expressjwt} = require("express-jwt")const app = express()
const secretKey = "kkk *_*"app.use(urlencoded({extended: false}))app.use(expressjwt({secret: secretKey,algorithms: ['HS256']}).unless({path: [/^\/api\//]})
)app.get("/api/login", (req, res) => {if (req.body.username === 'admin' && req.body.password === 'admin') {const tokenStr = jwt.sign({username: req.body.username}, secretKey, {expiresIn: "24h"})res.send({status: 200,msg: 'success',token: tokenStr})} else {req.send({msg: "账号或者密码错误"})}
})app.get("/user/getInfo", (req, res) => {res.send({status: 200,msg: "success",data: res.auth})
})app.listen(80, () => {console.log("server start")
})app.use((err, req, res, next) => {//token解析失败导致的错误if (err.name === 'UnauthorizedError') {return res.send({status: 401, message: '无效的token'})}//其它原因导致的错误res.send({status: 500, message: '未知错误'})
})
登录结果:
获取信息成功结果:
记得将登陆中得到的token放到Authorization中,并且前面加上Bearer
token有误的情况: