- vừa được xem lúc

Destroy jsonwebtoken sử dụng redis cùng loài mòe

0 0 34

Người đăng: Mòe vui vẻ

Theo Viblo Asia

1. Mở bài

Xin chào các bạn, lại là mòe vui vẻ đây. Rất nhiều ứng dụng Nodejs hiện nay sử dụng jsonwebtoken (JWT) để xác thực người dùng.

JWT là một phương tiện đại diện cho các yêu cầu chuyển giao giữa hai bên Client – Server , các thông tin trong chuỗi JWT được định dạng bằng JSON . Trong đó chuỗi Token phải có 3 phần là header , phần payload và phần signature được ngăn bằng dấu “.”

image.png

Các bạn có thể nhìn vào sơ đồ sau để hiểu hơn về cơ chế hoạt động của JWT

image.png

Mòe cũng theo xu hướng tập tọe học JWT, ban đầu thì rất nhàn và sướng. nhưng sau đó vấn đề bắt đầu xuất hiện khiến mòe nhiều đêm mất ngủ, nửa đêm vỗ gối, nước mắt đầm đìa tìm lời giải

2. Vấn đề của mòe

Thông thường, khi người dùng đăng xuất khỏi ứng dụng, người ta chỉ xóa JWT ở phía client. Thực thế, bạn vẫn có thể sử dụng token đó để request các API cho đến khi token đó hết hạn. Thời gian hiệu lực của JWT là cố định, bạn không thể set lại thời gian hiệu lực của token sau khi tạo. Vậy nên bạn không thể hủy token một cách thủ công được.

Sau khi tham khảo ý kiến từ người chị Gu Gồ thì mòe đã tìm ra được một vài cách để khắc phục vấn đề trên như:

  • Đặt thời gian hết hạn hợp lý cho token => chỉ khắc phục được phần nào thôi, với lại mòe không giỏi ước lượng lắm nên mòe bỏ qua.
  • Blacklist: Lưu lại toàn bộ token đã hết hạn hoặc không còn khả dụng nữa, khi xác thực thì kiểm tra token có trong blacklist không, nếu có thì tức là token này đã bị hủy => Cách này khá hay, nhưng nhước điểm là phải lưu vĩnh viễn đối với các token không set thời gian hiệu lực, hoặc phải lưu thời gian dài tùy theo thời hạn hiệu lực của token.

3. Hướng đi của mòe

So với ý tưởng blacklist ở trên thì mòe thấy dùng whitelist lại hay hơn phần nào. Đơn giản là khi tạo token thì ta lưu lại token đó vào whitelist và set TTL (Time To Live) trùng với thời gian hiệu lực của token. Khi xác thực token thì chỉ việc check thêm trên whitelist có token này không, nếu có thì token còn hiệu lực, không thì token đã bị hủy rồi. Khi token hết hạn thì bản ghi trên whitelist cũng tự xóa luôn, còn nếu muốn hủy thì đơn giản là ta chỉ cần xóa token này ở whitelist là xong.

4. Từ ý tưởng đến hành động

Ý tưởng đã rõ, mòe bắt tay vào test luôn cho nóng. Ở đây mòe sẽ lưu whitelist vào redis vì những ưu điểm không phải bàn cãi của nó.

  • Trước tiên thì cứ kết nối vào redis với package ioredis đã.
import Redis from 'ioredis' export const redis = new Redis({ host: '127.0.0.1', port: 6379, db: 0
}) redis.on('connect', function () { console.log('connected redis success!!!')
}) redis.on('error', function (err) { console.log('Connected redis Error ' + err)
})
  • Sau đó thì tạo class JwtRedis để quản lý jwt
import { redis } from './redis';
import jwt from 'jsonwebtoken' export default class JwtRedis { private readonly redisPrefix: string constructor(prefix: string) { this.redisPrefix = prefix } async sign( payload: string | object | Buffer, secretOrPrivateKey: jwt.Secret, options?: jwt.SignOptions ): Promise<string> { const token = jwt.sign(payload, secretOrPrivateKey, options) const decoded: any = jwt.decode(token) const key = `${this.redisPrefix}_${token}` // Nếu token này có expire time thì set TTL cho key if (decoded.exp) { const now = Date.now(); const duration = Math.floor(decoded.exp - (now / 1000)); if (duration > 0) { await redis.setex(key, duration, 'true'); } // Không thì cứ lưu nó đấy cho đến khi mình destroy thì thôi } else { await redis.set(key, 'true'); } return token } async verify(token: string) { const decoded: any = jwt.decode(token) const key = `${this.redisPrefix}_${token}` // Check xem trên redis có token này không const redisRecord = await redis.get(key) // Nếu không có thì token đã bị destroy rồi if (!redisRecord) throw new Error('Token destroyed!') return decoded } // Hủy token đi thì mình chỉ việc xóa key tương ứng trên redis thôi destroy = (token: string): Promise<number> => { const key = `${this.redisPrefix}_${token}` return redis.del(key); }
}
  • Cuối cùng là test xem có ưng cái bụng không
import JwtRedis from "./JwtRedis" (async () => { const jwtRedis = new JwtRedis('user') const token = await jwtRedis.sign( { id: 189278323 }, "yourSecret", { expiresIn: '1h' } ) console.log('token:', token) // token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTg5Mjc4MzIzLCJpYXQiOjE2NTI5NDE5NTUsImV4cCI6MTY1Mjk0NTU1NX0.KO3w8WP5JaZXOrR1Bov1iH7-e3KGbog2JdQhNZmI9Kw const decode = await jwtRedis.verify(token) console.log('decode:', decode) // decode: { id: 189278323, iat: 1652941955, exp: 1652945555 } await jwtRedis.destroy(token) const decodeAfterDestroy = await jwtRedis.verify(token) // Error: Token destroyed! console.log('decodeAfterDestroy: ', decodeAfterDestroy)
})()

Ngon lành cành đào luôn. Vậy là sau này mình chỉ việc dùng class JwtRedis để tạo và quản lý token là được.


Nếu các bạn thấy bài viết hay và có ích, hãy upvote cho mòe nhé. Bạn nào có cách làm hay hơn thì có thể comment dưới bài để mòe tham khảo.

Xin cảm ơn các bạn đã dành thời gian đọc bài của mòe và hẹn gặp lại các bạn trong những bài viết sau.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 374

- vừa được xem lúc

Hướng dẫn làm bot Facebook messenger cho tài khoản cá nhân

Giới thiệu. Trong bài viết trước thì mình có hướng dẫn các bạn làm chatbot facebook messenger cho fanpage. Hôm nay mình sẽ hướng dẫn các bạn tạo chatbot cho một tài khoản facebook cá nhân. Chuẩn bị.

0 0 146

- vừa được xem lúc

Crawl website sử dụng Node.js và Puppeteer - phần 2

trong phần 1 mình đã giới thiệu về puppeteer và tạo được 1 project cùng một số file đầu tiên để các bạn có thể crawl dữ liệu từ một trang web bất kỳ. Bài này mình sẽ tiếp nối bài viết trước để hoàn thiện seri này.

0 0 58

- vừa được xem lúc

Điều React luôn giữ kín trong tim

■ Mở đầu. Ngồi viết bài khi đang nghĩ vu vơ chuyện con gà hay quả trứng có trước, mình phân vân chưa biết sẽ chọn chủ đề gì để chúng ta có thể cùng nhau bàn luận.

0 0 42

- vừa được xem lúc

Gửi Mail với Nodejs và AWS SES

AWS SES. AWS SES là gì.

0 0 71

- vừa được xem lúc

Crawl website sử dụng Node.js và Puppeteer - phần 1

Bài viết này mình sẽ giới thiệu cho các bạn craw dữ liệu của web site sử dụng nodejs và Puppeteer. .

0 0 149