实现token验证主要有以下步骤:
- 前端登录时携带用户名和密码发送到后端
- 后端根据用户名和密码进行验证,如果验证通过,生成一个token信息发送到前端
- 前端接受到响应之后将token信息保存下来
- 之后所有的前端请求都需要通过头信息将token信息携带上
- 后端接受到token之后进行验证和解析,能够通过才返回响应
接下来详细介绍:
首先我们会使用插件JWT插件(JSON WEB TOKEN);
一种生成加密字段的工具插件;可以在加密时添加载荷信息以便解析时进行验证;可以设置token的有效期,过了有效期之后就需要重新登录。
例如我们在vue+egg前后端项目中实现token验证使用JWT插件:
1.egg项目中安装配置JWT:
npm i egg-jwt --save //下载插件
// {app_root}/config/plugin.js 配置
exports.jwt = {
enable: true,
package: "egg-jwt"
};//可以理解为秘钥
exports.jwt = {
secret: "123456"
};
2.在登录成功之后,后端生成并返回token信息给前台;
const token = app.jwt.sign({ username: body.username, password: body.password }, app.config.jwt.secret, { expiresIn: '1h' })
//第一个参数是一个对象,我们可以将我们的用户名和密码存进去,第二个参数是拿到配置的secret,第三个是过期时间等等,
3.在 sessionStorage中存储token;
sessionStorage.setItem("token", res.data.token as string);
4.给axios添加拦截器,请求拦截,在请求拦截器中将token携带上;
// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
if (sessionStorage.token) {
if (config.headers) {
//在请求前,我们将sessionStorage中的token设置到我们的请求头上,发送请求,一块发给后台
config.headers.authorization = sessionStorage.token;
}
}
return config;
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error);
}
);
5.在后端通过中间件进行判断;(一般使用路由级中间件);
module.exports = function (options, app) {
return async function (ctx, next) {
let auth = ctx.request.header.authorization
if (auth) {
const res = ctx.app.jwt.verify(auth, ctx.app.config.jwt.secret);
// console.log(res);
const obj = ctx.service.user.checkOne(res.username, res.password);
// console.log(obj);
if (obj) {
await next()
} else {
ctx.body = {
msg: "token错误或者过期",
code: 402,
}
}
} else {
ctx.body = {
msg: "缺少token信息",
code: 401,
}
}
// await next()
}
}
后台每次访问路由,然后设置路由级中间件,在中间件中我们拿到我们的token信息,使用jwt.verify去将我们的token令牌解密,会拿到我们刚开始设置的用户名密码,秘钥、过期时间等等,然后我们可以将用户名和密码作为参数去调用服务去数据库查询是否正确,来决定是否通过该中间件,如果不对的话,我们可以返给前台token错误或者过期,如果都没有拿到token信息的话,则返回缺少token信息
6.前端也可以通过响应拦截对结果进行预处理;
// 添加响应拦截器
axios.interceptors.response.use(
function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
if (response.data.code === 401 || response.data.code === 402) {
ElMessage.error(response.data.msg);
sessionStorage.removeItem("login");
router.push("/login");
}
return response;
},
function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
}
);
在拿到响应结果前,我们也可以进行拦截,去判断是否有code为401或者402,即为我们的token信息不存在或者错误时间过期等等,如果存在这些情况,则我们就不能让该用户继续访问,则给出相应的提示,然后删除我们的login信息,然后我们就可以路由跳转到登录页。