JWT(JSON Web Token),本质就是一个字符串书写规范,作用是用来在用户和服务器之间传递安全可靠的信息。
jwt 鉴权的作用
我们在前端通过路由导航配置了路由的权限,但是对应的后端接口依然是可以直接发送请求的,所以我们需要通过 jwt 鉴权来判断接口是否可以发送请求。
jwt 鉴权主要包括两个方面:
-
用户登录之后的鉴权设置
-
登录状态过期的验证
前端实现思路
用户登录之后的鉴权设置
当我们登录成功之后,后端会返回一个 token,我们把这个 token 存储到浏览器中。在每次发送请求之前判断请求头里是否存在 token,如果请求头里没有 token 且可以从浏览器中获取到 token 值,则说明用户已登录,这时给请求头设置 token 值。
// 登录成功保存 token
login({ username, password }).then((res) => {
window.localStorage.setItem("token", res.token);
})
// 请求拦截器
service.interceptors.request.use(
(config) => {
const token = window.localStorage.getItem("token");
if (!config.headers.Authorization && token) {
config.headers.Authorization = "Bearer " + token;
}
return config;
},
(error) => {
Promise.reject(error);
}
);
登录状态过期
如果后端判断登录的状态已过期,即 token 值过期,会返回 401,前端就可以在响应拦截器里面做一些处理操作,例如移除 token,跳转到登录页重新登录。
service.interceptors.response.use(
(res) => {
const code = res.data.code || 200;
const msg = res.data.msg;
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true;
// 弹出提示框
MessageBox.confirm(
"登录状态已过期,您可以继续留在该页面,或者重新登录",
"系统提示",
{
confirmButtonText: "重新登录",
cancelButtonText: "取消",
type: "warning",
}
)
.then(() => {
isRelogin.show = false;
// 删除保存在浏览器里的 token
window.localStorage.removeItem("token");
location.href = "/index";
})
.catch(() => {
isRelogin.show = false;
});
}
return Promise.reject("无效的会话,或者会话已过期,请重新登录。");
}
return res.data;
}
);
后端实现思路
在 Node.js 中我们可以使用 jsonwebtoken 包来生成及校验 token
// 1. 导入包
const jwt = require('jsonwebtoken')
// 2. 定义密钥
const KEY = 'qwerty'
// 3. 定义载荷
const data = { username: '' }
// 4. 生成 token
const token = jwt.sign(data, KEY, {
expiresIn: 60, // 设置过期时间
})
// 5. 校验 token 是否过期
jwt.verify(token, KEY, (err, data) => {
if (err) {
console.log('校验失败')
return
}
console.log(data)
}
用户登录之后的鉴权设置
用户验证通过之后生成 token,然后返回该 token 值
const jwt = require('jsonwebtoken')
const KEY = 'qwerty'
router.post('/login', (req, res) => {
// 用户验证通过
const token = jwt.sign({ username: req.body.username }, KEY, { expiresIn: 60 })
})
登录状态过期
添加一个全局的路由中间件,判断 token 值是否过期
const jwt = require('jsonwebtoken')
const KEY = 'qwerty'
// 注册路由中间件
app.use((req, res, next) => {
const token = req.get('authorization').split(' ')[1]
// 判断是否登录
if (!token) {
res.json({
code: 500,
msg: '验证不通过',
})
} else {
// 验证 token 是否过期
jwt.verify(token, KEY, (err, data) => {
if (err) {
res.json({
code: 401,
msg: '登录已过期',
})
return
}
// 保存用户信息
req.user = data
next()
})
}
})