JWT 简单的原理介绍
JWT(Json Web Token)是一种身份验证及授权方案,简单的说就是调用端调用 api 时,附带上一个由 api 端颁发的 token,以此来验证调用者的授权信息。
通过一种加密规则(如 HS256)+ secret 生成一串字符串(token),token 字符串中一般含有过期时间和签名信息,根据签名和过期时间,就可以判断当前 token 是否有效。
// newToken是根据 'jwt_secret' 生成的, jws.verify用于校验当前token是否是根据当前secret生成的
console.log(jws.verify(newToken, 'HS256', 'jwt_secret')); // true
console.log(jws.verify(newToken, 'HS256', '-=-=-=')); // false
无论使用哪个 secret 生成的 token,都是可以解析到 payload 的内容的,仅仅只是签名不同,
payload 的常见内容:
{
uuid: "3455445-acuya7skeasd-iue7", // token的有效内容
phone: 133409899625, // token的有效内容
expires: 1591066434678, // token的过期时间
},[signature]
根据 expires 判断 token 是否过期,根据 signature 判断当前 token 是否时本人创建,根据这两点就可以判断 token 是否有效了。
更详细的介绍,可参考:https://jwt.io/。
NodeJS 中如何应用 JWT
1. 安装 jsonwebtoken
npm install jsonwebtoken --save
PS: 也可以安装 jws,jsonwebtoken 是基于 jws 进行封装的,简化了使用方式。
2.封装 JWT 函数
import jsonwebtoken from 'jsonwebtoken';
const secret = 'test_key';
export default class JWT {
public static generate(value: any, expires = '7 days'): string { // value 为传入值, expires为过期时间,这两者都会在token字符串中题先
try {
return jsonwebtoken.sign(value, secret, { expiresIn: expires });
} catch (e) {
console.error('jwt sign error --->', e);
return '';
}
}
public static verify(token: string) {
try {
return jsonwebtoken.verify(token, secret); // 如果过期将返回false
} catch (e) {
console.error('jwt verify error --->', e);
return false;
}
}
}
测试 JWT 方法,开发中建议使用 Jest 等工具写点单元测试,这里就简化了....
const payload = {
uuid: '3455445-acuya7skeasd-iue7',
phone: 133409899625,
};
const token = JWT.generate(payload, '12s');
const info = JWT.verify(token);
console.log(token);
console.log(info);
setTimeout(() => {
console.log('检验过期token');
const info2 = JWT.verify(token);
console.log(info2); // false
}, 13000);
/*
控制台打印:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dWlkIjoiMzQ1NTQ0NS1hY3V5YTdza2Vhc2QtaXVlNyIsInBob25lIjoxMzM0MDk4OTk2MjUsImlhdCI6MTU5MDk5MDQwOSwiZXhwIjoxNTkxMDc2ODA5fQ.VEjIlQFEw4arU7jR54M6MYR7KMDx-VAlX_CcfmusKeU
{
uuid: '3455445-acuya7skeasd-iue7', // 传入的数据
phone: 133409899625, // 传入的数据
iat: 1590990409,
exp: 1591076809 // 过期时间,不需要我们进行判断jsonwebtoken会帮我们进行过期校验,如果过期会返回false
}
*/
3. 封装自动校验的中间件
import { Context, Next } from 'koa';
import { JWT } from '../utils';
const Auth = async (ctx: Context, next: Next) => {
const { authorization = '' } = ctx.request.header;
const token = authorization.replace('Bearer ', '');
const info = JWT.verify(token);
if (info) {
ctx.state.info = info; // 将信息存放到 state 中
} else {
ctx.throw(401, 'token error');
}
await next();
};
export default Auth;
4. 在 router 中使用
import Router from 'koa-router';
import UserController from '../controllers/user';
import Auth from '../middleware/auth'
const router = new Router<DefaultState, Context>({prefix: '/v1.0'});
router.post("/check", Auth, UserController.check); //只有通过 Auth 检测,才会进入 check 函数
router.post("/sendOTP", UserController.sendOTP);
export default router;
5. 在 Controller 中获取校验后的信息
...
async check(ctx: Context) {
const { mobile, uuid } = ctx.state.info; // 获取 Auth 中传递的数据
const result = await getInfo(uuid); // 获取数据库中的用户信息,getInfo 是封装的公用方法,这里旧暂略了
const token = JWT.generate({ mobile, uuid }, '1d'); // 更新 token 时间(生成一条新的 token,旧的 token 任然是可以使用的)
const data = Object.assign({}, result, { token });
ctx.body = {
status:200,
message: 'Success',
result: data
}
}
...
6. 前端传递 token
前端使用 axios 进行数据发送
import axios from 'axios';
axios.defaults.withCredentials = true;
// 将 token 放到拦截器里面处理
axios.interceptors.request.use(function (config) {
const requestToken = getCookie('token'); // 获取我们存储的 token
config.headers['Authorization'] = 'Bearer ' + requestToken; // 将 token 放到 header 里面
config.headers.post['Content-Type'] = 'application/json';
config.timeout = 60000;
return config;
});
至此,NodeJS中使用 JWT 就算完成了。。。。