refactor: Replaced dynamic rate limit creation with pre-configured role-based limiters.
This commit is contained in:
@@ -1,11 +1,93 @@
|
||||
import { logger } from '@goodgo/logger';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { RedisStore } from 'rate-limit-redis';
|
||||
|
||||
import { getRedisClient } from '../config/redis.config';
|
||||
import { rbacService } from '../modules/rbac/rbac.service';
|
||||
|
||||
/**
|
||||
* EN: Pre-configured rate limiters for different user tiers
|
||||
* VI: Rate limiters được cấu hình trước cho các cấp độ người dùng khác nhau
|
||||
*/
|
||||
const superAdminLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 1000,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
handler: (_req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const adminLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 500,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
handler: (_req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const moderatorLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 300,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
handler: (_req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const userLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 100,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
handler: (_req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const guestLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 50,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
handler: (_req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* EN: Dynamic rate limiting based on user role
|
||||
* VI: Giới hạn tốc độ động dựa trên vai trò người dùng
|
||||
@@ -18,58 +100,25 @@ export const dynamicRateLimit = async (
|
||||
try {
|
||||
const userId = (req as any).user?.id || (req as any).user?.sub;
|
||||
|
||||
// Default limits
|
||||
let windowMs = 15 * 60 * 1000; // 15 minutes
|
||||
let max = 100; // 100 requests
|
||||
let limiter = guestLimiter;
|
||||
|
||||
if (userId) {
|
||||
// Get user roles
|
||||
const roles = await rbacService.getUserRoles(userId);
|
||||
|
||||
// Set limits based on role
|
||||
// Select limiter based on role
|
||||
if (roles.includes('SUPER_ADMIN')) {
|
||||
windowMs = 15 * 60 * 1000;
|
||||
max = 1000;
|
||||
limiter = superAdminLimiter;
|
||||
} else if (roles.includes('ADMIN')) {
|
||||
windowMs = 15 * 60 * 1000;
|
||||
max = 500;
|
||||
limiter = adminLimiter;
|
||||
} else if (roles.includes('MODERATOR')) {
|
||||
windowMs = 15 * 60 * 1000;
|
||||
max = 300;
|
||||
limiter = moderatorLimiter;
|
||||
} else {
|
||||
// Regular user
|
||||
windowMs = 15 * 60 * 1000;
|
||||
max = 100;
|
||||
limiter = userLimiter;
|
||||
}
|
||||
} else {
|
||||
// Unauthenticated users - stricter limits
|
||||
windowMs = 15 * 60 * 1000;
|
||||
max = 50;
|
||||
}
|
||||
|
||||
// Create rate limiter
|
||||
const limiter = rateLimit({
|
||||
windowMs,
|
||||
max,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new RedisStore({
|
||||
// @ts-expect-error - rate-limit-redis types mismatch with ioredis
|
||||
sendCommand: (...args: string[]) => getRedisClient().call(...args),
|
||||
prefix: 'rl:',
|
||||
}),
|
||||
handler: (_req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Apply rate limiter
|
||||
// Apply selected rate limiter
|
||||
limiter(req, res, next);
|
||||
} catch (error) {
|
||||
logger.error('Rate limit middleware error', { error });
|
||||
|
||||
Reference in New Issue
Block a user