react博客-egg-jwt实现登录系统
🚧 🚧提示
本文最后于 2020年5月13日 更新,部分内容可能已经过时,请在阅读本文时注意参考最新的信息。
react 博客系列文章
何为 jwt
egg-jwt
安装 egg-jwt
yarn add egg-jwt
配置 egg-jwt
- 配置
config/plugin.js
文件
exports.jwt = {
enable: true,
package: 'egg-jwt'
};
- 配置
config/config.default.js
文件
// 自己设定的密钥,用于对信息进行签名
config.jwt = {
secret: 'xxxxxx'
};
实例
后台实现登录操作返回 token
- 路由层
在第二个参数上加上 jwt 即可实现对该路由的鉴权
下面的 jwt 是自定义的中间件auth.js
,该文件在下一部分介绍
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller, middleware, config } = app;
const { admin } = controller.admin;
const jwt = middleware.auth(config.jwt);
router.post('/admin/login', admin.login);
// 需要鉴权的路由再第二个参数上加上jwt
router.get('/admin/get_type_list', jwt, admin.getTypeList);
};
- controller 层
使用jwt.sign(加密数据, 密钥, [options, callback])
来生成 token
相关配置可以查看jsonwebtoken
async login() {
const { app, ctx } = this;
const { username, password } = ctx.request.body;
const checkValidate = await ctx.service.admin.admin.checkUserValidate(username, password);
if (checkValidate) {
// 将信息使用jwt进行签名加密生成token,expiresIn(token有效时间)
const token = app.jwt.sign({ username, password }, app.config.jwt.secret, { expiresIn: '2h' });
ctx.body = {
code: '0001',
msg: '登录成功',
token,
};
} else {
ctx.body = {
code: '0002',
msg: '用户名或者密码错误,请重试!',
};
}
}
- service 层
async checkUserValidate(username, password) {
const isValidate = await this.app.mysql.get('admin', { username, password });
return !!isValidate;
}
- 使用 postman 进行测试
将生成的 token 返回给前台后使用localStorage.setItem
把token
保存到本地
前台传递 token 进行鉴权
封装 axios
新建 axios 文件对 axio 进行封装,通过 axios 的拦截器来实现每次请求时自动在 headers 上携带 token 数据到后台,后台使用jwt.verify
来检验 token 的正确性
axios.js
import axios from 'axios';
axios.interceptors.request.use(config => {
// 登录成功后保存在本地的token
const token = localStorage.getItem('token');
config.headers.Authorization = `Bearer ${token}`;
return config;
});
axios.interceptors.response.use(response => {
// code是后台接口设置的
const { code } = response.data;
if (code === '0003' || code === '0004') {
window.location.href = '/login';
}
return response;
});
export default axios;
封装好后,之后都使用该封装好后的 axios 进行请求。
后台校验处理
auth.js
'use strict';
module.exports = options => {
return async function auth(ctx, next) {
// 获取前台通过axios封装后穿过来的token
const token = ctx.header.authorization;
if (token) {
try {
// 验证并对token进行解码
const decode = ctx.app.jwt.verify(token.split(' ')[1], options.secret);
console.log(decode);
await next();
} catch (error) {
console.log(error.name);
if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
// 这里的错误有许多种情况:1.token错误,2.token过期... 这里统一处理为鉴权失败
ctx.body = {
code: '0003',
msg: '用户鉴权失败,请重新登录'
};
} else {
throw error;
}
}
} else {
ctx.body = {
code: '0004',
msg: '您没有登录,请先登录'
};
}
};
};
后台通过/middleware/auth.js
中间件来实现给需要鉴权的接口进行鉴权,通过对前台传过来的 token 数据进行验证jwt.verify
来识别登录状态。对JsonWebTokenError
错误统一处理,应为auth.js
作为中间件,所以接口中出现的其他错误也会在这里被 catch 到,对于不是JsonWebTokenError
的错误,直接把错误抛出去。