JWT
JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
流程图:
例子
工具代码(下面代码会用到)
class Utils {
CallbackModel(ctx, status, message, data) {
ctx.response.status = status;
ctx.body = {
code: status,
message: message,
data: data,
};
}
}
module.exports = new Utils;
1. 创建token
- 登录接口
const { secret } = require('../config'); // secret 就是一个变量,自己定义名称即可
const jwt = require('jsonwebtoken');
// 登录
async login(ctx) {
ctx.verifyParams({
name: { type: 'string', required: true },
password: { type: 'string', required: true },
});
try {
const user = await User.findOne(ctx.request.body);
if (!user) {
CallbackModel(ctx, 404, '请输入正确账号密码', {})
return;
}
// jwt 签发
const { _id, name } = user;
const token = jwt.sign({ _id, name }, secret, { expiresIn: '1d' });
CallbackModel(ctx, 200, '登录成功', { token, name })
} catch (err) {
CallbackModel(ctx, 500, '错误', JSON.stringify(err))
}
}
2. 验证token
这个 auth
是 koa-jwt 已经写好的中间件,但是下图展示返回结果不是很友好,so,我们得手动写一个auth中间件的方法
- postman调试结果
3. 编写auth.js 的中间件,中间件的返回的结果需要是function类型
- 创建 middleware/auth.js
- 编写代码
const jwt = require('jsonwebtoken');
const util = require('util');
const { CallbackModel } = require('../utils')
const { secret } = require('../config');
const verify = util.promisify(jwt.verify);
module.exports = function() {
return async function(ctx, next) {
try {
const { authorization = '' } = ctx.request.header;
const token = authorization.split(' ')[1];
if (!token) {
CallbackModel(ctx, 404, '缺失Token信息', {})
return;
}
try {
// 解密payload,获取用户名和ID
const payload = await verify(token, secret);
ctx.state = {
name: payload.name,
_id: payload._id,
};
await next(); //运行完毕,交给下一个中间件
} catch (err) {
if (JSON.stringify(err).search(/JsonWebTokenError/)) {
CallbackModel(ctx, 401, 'Token无效', JSON.stringify(err))
} else {
CallbackModel(ctx, 500, '未知错误', JSON.stringify(err))
}
}
} catch (err) {
CallbackModel(ctx, 500, '错误', JSON.stringify(err))
}
}
}
- 使用auth的中间件(routes/users.js)
- postman调试结果
这个auth中间是那个路由需要校验,就引入该方法,比如下的方法简单多了
// app.js
const koa = require('koa');
app.use(koajwt({
secret: 'my_token'
}).unless({
path: [/\/user\/login/]
}));
总结:
安全性
- 如果 JWT 的加密密钥泄露的话,那么就可以通过密钥生成 token,随意的请求 API 了。因此密钥绝对不能存在前端代码中,不然很容易就能被找到。
- 在 HTTP 请求中,token 放在 header 中,中间者很容易可以通过抓包工具抓取到 header 里的数据。而 HTTPS 即使能被抓包,但是它是加密传输的,所以也拿不到 token,就会相对安全。