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 就算完成了。。。。