NodeJS 基於 JWT 實現身份驗證(token、自動登陸)


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM