在 egg 框架中使用 egg-jwt 实现登录鉴权。
1. egg-jwt 的配置使用
gihub地址:https://github.com/okoala/egg-jwt
1.1 安装 egg-jwt 依赖
npm install egg-jwt egg-cors --save
egg-cors 处理跨域问题,这里搭配使用。
1.2 增加egg-jwt相关配置
在 plugin.ts 中增加配置如下:
import { EggPlugin } from 'egg';
const plugin: EggPlugin = {
..., // 其他插件配置
jwt: {
enable: true,
secret: "123456"//自定义 token 的加密条件字符串
package: "egg-jwt"
},
cors: {
enable: true,
package: 'egg-cors',
}
..., // 其他插件配置
};
export default plugin;
1.3 登录时生成token,获取token信息
在 controler 中处理登录生成 token 返回给前端,使用app.jwt.sign生成token,通过 ctx.state.user 获取token 里的用户信息示例代码如下:
import { Controller } from 'egg';
export default class AdminController extends Controller {
// 验证登录并且生成 token
public async login() {
const { ctx ,app} = this;
//获取用户端传递过来的参数
const data = ctx.request.body;
// 进行验证 data 数据 登录是否成功
// .........
//成功过后进行一下操作
//生成 token 的方式
const token = app.jwt.sign({
username: data.username, //需要存储的 token 数据
//......
}, app.config.jwt.secret);// 生成的token = akjsndk******aksjdnka
// 返回 token 到前端
ctx.body = token;
};
//访问admin数据时进行验证token,并且解析 token 的数据
public async index() {
const { ctx ,app} = this;
console.log(ctx.state.user);
/*
* 打印内容为:{ username : 'admin', iat: 1560346903 }
* iat 为过期时间,可以单独写中间件验证,这里不做细究
* 除了 iat 之后,其余的为当时存储的数据
**/
ctx.body = {code:0,msg:'验证成功'};
}
}
可以通过 ctx.state.user 是否有数据来进行登录判断,逻辑可放在egg 中间件中统一处理。
// 方法一:在应用中使用中间件
config.middleware = [ 'jwt' ]
config.jwt = {
enable: true,
ignore: [ '/api/v1/test/', '/public/' ],// 哪些请求不需要认证
}
// 方法二:router中使用中间件
module.exports = app => {
const jwt = app.middleware.jwt();
app.router.get('/api/v1/test/', jwt, app.controller.test.test);
};
1.4 前端使用 token
前端在请求的header中放入 token 即可,示例如下:
{
...// 其他header
Authorization: `Bearer ${token}`
}
2. 常见问题
2.1 ctx.state.user 始终没有数据
检查 egg-jwt 插件是否启用,plugin.js 配置文件里的 enable 为 true 才行:
const plugin: EggPlugin = {
..., // 其他插件配置
jwt: {
enable: true, // 必须为true才能开启
secret: "123456"//自定义 token 的加密条件字符串
package: "egg-jwt"
},
2.2 token 过期处理
token 过期有如下报错:
2023-07-11 22:54:38,000 WARN 23548 [-/127.0.0.1/-/9ms GET /api/method] nodejs.UnauthorizedError: invalid signature
at D:\workspace\farmer-server\node_modules\koa-jwt2\lib\index.js:117:18
at D:\workspace\farmer-server\node_modules\jsonwebtoken\verify.js:133:14
at getSecret (D:\workspace\farmer-server\node_modules\jsonwebtoken\verify.js:90:14)
at Object.module.exports [as verify] (D:\workspace\farmer-server\node_modules\jsonwebtoken\verify.js:94:10)
at decoded (D:\workspace\farmer-server\node_modules\koa-jwt2\lib\index.js:115:11)
at new Promise (<anonymous>)
at middleware (D:\workspace\farmer-server\node_modules\koa-jwt2\lib\index.js:114:27)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at D:\workspace\farmer-server\node_modules\egg-development\app\middleware\egg_loader_trace.js:9:50
name: "UnauthorizedError"
message: "invalid signature"
code: "invalid_token"
status: 401
inner: {"name":"JsonWebTokenError","message":"invalid signature"}
pid: 23548
hostname: DESKTOP-GQ0K6U1
捕获错误,正常返回 过期状态即可,异常捕获详见:https://github.com/eggjs/egg-onerror
2.3 不需要登录鉴权的路由请配置中间件的 ignore
不传 token 的情况或者token 格式不对,都会报 401 的错误,所以不需要登录的路由请配置中间件的 ignore 或者match,来避免 egg-jwt 组件去读取 token。