Trong bối cảnh bảo mật ứng dụng web ngày nay, việc xác thực người dùng và quản lý quyền truy cập là rất quan trọng. JSON Web Tokens (JWT) đã trở thành một phương pháp phổ biến để thực hiện xác thực. Tuy nhiên, khi sử dụng JWT, có một vấn đề phát sinh liên quan đến việc quản lý blacklist cho những token không còn hợp lệ. Trong bài viết này, chúng ta sẽ khám phá cách xác thực JWT trong Node.js và cách sử dụng Redis để quản lý blacklist một cách hiệu quả.
Danh mục bài viết
ToggleJWT là gì?
Một JWT bao gồm ba phần:
- Header: Thông tin về loại token và thuật toán mã hóa.
- Payload: Chứa thông tin về người dùng và quyền hạn (claims).
- Signature: Được tạo bằng cách mã hóa header và payload cùng với một khóa bí mật.
Tại sao cần quản lý Blacklist?
Mặc dù JWT có ưu điểm là không cần lưu trữ trạng thái trên server (stateless), nhưng khi một token bị thu hồi (ví dụ: người dùng đăng xuất), cần có cơ chế để quản lý những token này. Nếu không, những token đã bị thu hồi vẫn có thể được sử dụng để truy cập vào tài nguyên.
Đây chính là lý do tại sao chúng ta cần sử dụng blacklist. Blacklist sẽ lưu trữ danh sách các JWT đã bị thu hồi để không cho phép chúng được sử dụng nữa.
Cách kết hợp JWT với Redis quản lý Blacklist trong Node.js
Bạn có thể làm theo các bước ở phía dưới hoặc xem video của anh Tips Javascript một người rất nổi tiếng trong việc tối ưu perfomance
Nguồn Tips Javascript
Bước 1: Cài đặt các gói cần thiết
Trước tiên, bạn cần cài đặt các gói npm cần thiết cho dự án Node.js của mình:
npm install express jsonwebtoken redis dotenv
Bước 2: Thiết lập Redis
Khởi động một phiên bản Redis. Nếu bạn chưa có Redis, có thể tải và cài đặt Redis từ trang chủ của Redis.
Sau khi cài đặt xong, bạn có thể kiểm tra bằng cách chạy lệnh:
redis-server
Bước 3: Tạo ứng dụng Node.js
Tạo một file app.js
và cấu hình Express cùng với JWT và Redis.
const express = require('express');
const jwt = require('jsonwebtoken');
const redis = require('redis');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
const redisClient = redis.createClient();
redisClient.on('error', (err) => {
console.error('Redis error: ', err);
});
app.use(express.json());
// Khóa bí mật cho JWT
const SECRET_KEY = process.env.SECRET_KEY || 'your_secret_key';
// Hàm tạo token
const generateToken = (userId) => {
return jwt.sign({ id: userId }, SECRET_KEY, { expiresIn: '1h' });
};
// Middleware kiểm tra token
const authenticateJWT = (req, res, next) => {
const token = req.header('Authorization')?.split(' ')[1];
if (!token) return res.sendStatus(401);
// Kiểm tra blacklist
redisClient.get(token, (err, reply) => {
if (reply) return res.sendStatus(401); // Token bị chặn
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
});
};
// Đăng nhập và tạo token
app.post('/login', (req, res) => {
const { username } = req.body; // Giả sử bạn có một trường username
const token = generateToken(username);
res.json({ token });
});
// Đăng xuất (thu hồi token)
app.post('/logout', authenticateJWT, (req, res) => {
const token = req.header('Authorization').split(' ')[1];
// Lưu token vào Redis để blacklist
redisClient.set(token, 'blacklisted', 'EX', 3600); // Thời gian sống 1 giờ
res.sendStatus(200);
});
// Route bảo vệ
app.get('/protected', authenticateJWT, (req, res) => {
res.send('This is a protected route.');
});
// Khởi động server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Giải thích mã nguồn
- Cài đặt Redis: Kết nối đến Redis và xử lý các lỗi kết nối.
- Tạo token: Hàm
generateToken
tạo JWT cho người dùng với thời gian hết hạn là 1 giờ. - Middleware kiểm tra JWT: Middleware
authenticateJWT
sẽ kiểm tra xem token có tồn tại trong Redis không. Nếu có, nghĩa là token đã bị thu hồi và sẽ trả về lỗi 401. Nếu không, nó sẽ xác thực token và tiếp tục xử lý yêu cầu. - Đăng xuất: Khi người dùng đăng xuất, token sẽ được thêm vào Redis blacklist với thời gian sống (TTL) là 1 giờ.
- Route bảo vệ: Route
/protected
sẽ chỉ cho phép truy cập nếu token là hợp lệ và không nằm trong blacklist.
Kết luận
Việc xác thực JWT trong Node.js kết hợp với Redis để quản lý blacklist mang lại một phương pháp bảo mật hiệu quả cho ứng dụng của bạn. Nó không chỉ giúp kiểm soát quyền truy cập mà còn bảo vệ tài nguyên của bạn khỏi các token không hợp lệ. Hãy áp dụng cách tiếp cận này để nâng cao mức độ bảo mật cho ứng dụng của bạn!