mirror of
https://github.com/ZeroCatDev/ClassworksKV.git
synced 2025-10-22 18:33:11 +00:00
200 lines
6.5 KiB
JavaScript
200 lines
6.5 KiB
JavaScript
import rateLimit from "express-rate-limit";
|
||
|
||
// 获取客户端真实IP的函数
|
||
export const getClientIp = (req) => {
|
||
return (
|
||
req.headers["x-forwarded-for"] ||
|
||
req.connection.remoteAddress ||
|
||
req.socket.remoteAddress ||
|
||
req.connection.socket?.remoteAddress ||
|
||
"0.0.0.0"
|
||
);
|
||
};
|
||
|
||
// 从请求中提取Token的函数
|
||
const extractToken = (req) => {
|
||
return (
|
||
req.headers["x-app-token"] ||
|
||
req.query.apptoken ||
|
||
req.body?.apptoken ||
|
||
null
|
||
);
|
||
};
|
||
|
||
// 获取限速键:优先使用token,没有token则使用IP
|
||
export const getRateLimitKey = (req) => {
|
||
const token = extractToken(req);
|
||
if (token) {
|
||
return `token:${token}`;
|
||
}
|
||
return `ip:${getClientIp(req)}`;
|
||
};
|
||
|
||
// 配置全局限速中间件
|
||
export const globalLimiter = rateLimit({
|
||
windowMs: 15 * 60 * 1000, // 15分钟
|
||
limit: 200, // 每个IP在windowMs时间内最多允许200个请求
|
||
standardHeaders: "draft-7", // 返回标准的RateLimit头信息
|
||
legacyHeaders: false, // 禁用X-RateLimit-*头
|
||
message: "请求过于频繁,请稍后再试",
|
||
keyGenerator: getClientIp, // 使用真实IP作为限速键
|
||
skipSuccessfulRequests: false, // 成功的请求也计入限制
|
||
skipFailedRequests: false, // 失败的请求也计入限制
|
||
});
|
||
|
||
// API限速器
|
||
export const apiLimiter = rateLimit({
|
||
windowMs: 1 * 60 * 1000, // 1分钟
|
||
limit: 100, // 每个IP在windowMs时间内最多允许100个请求
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "API请求过于频繁,请稍后再试",
|
||
keyGenerator: getClientIp,
|
||
skipSuccessfulRequests: false,
|
||
skipFailedRequests: false,
|
||
});
|
||
|
||
// 写操作限速器(更严格)
|
||
export const writeLimiter = rateLimit({
|
||
windowMs: 1 * 60 * 1000, // 1分钟
|
||
limit: 20, // 每个IP在windowMs时间内最多允许20个写操作
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "写操作请求过于频繁,请稍后再试",
|
||
keyGenerator: getClientIp,
|
||
skipSuccessfulRequests: false,
|
||
skipFailedRequests: false,
|
||
});
|
||
|
||
// 删除操作限速器(最严格)
|
||
export const deleteLimiter = rateLimit({
|
||
windowMs: 1 * 60 * 1000, // 5分钟
|
||
limit: 10, // 每个IP在windowMs时间内最多允许10个删除操作
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "删除操作请求过于频繁,请稍后再试",
|
||
keyGenerator: getClientIp,
|
||
skipSuccessfulRequests: false,
|
||
skipFailedRequests: false,
|
||
});
|
||
|
||
// 认证相关路由限速器(防止暴力破解)
|
||
export const authLimiter = rateLimit({
|
||
windowMs: 30 * 60 * 1000, // 30分钟
|
||
limit: 5, // 每个IP在windowMs时间内最多允许5次认证尝试
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "认证请求过于频繁,请30分钟后再试",
|
||
keyGenerator: getClientIp,
|
||
skipSuccessfulRequests: true, // 成功的认证不计入限制
|
||
skipFailedRequests: false, // 失败的认证计入限制
|
||
});
|
||
|
||
// 批量操作限速器(比写操作更严格)
|
||
export const batchLimiter = rateLimit({
|
||
windowMs: 1 * 60 * 1000, // 5分钟
|
||
limit: 10, // 每个IP在windowMs时间内最多允许10个批量操作
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "批量操作请求过于频繁,请稍后再试",
|
||
keyGenerator: getClientIp,
|
||
skipSuccessfulRequests: false,
|
||
skipFailedRequests: false,
|
||
});
|
||
|
||
// === Token 专用限速器(更宽松的限制) ===
|
||
|
||
// Token 读操作限速器
|
||
export const tokenReadLimiter = rateLimit({
|
||
windowMs: 1 * 60 * 1000, // 1分钟
|
||
limit: 1024, // 每个token在1分钟内最多1024次读操作
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "读操作请求过于频繁,请稍后再试",
|
||
keyGenerator: getRateLimitKey,
|
||
skipSuccessfulRequests: false,
|
||
skipFailedRequests: false,
|
||
});
|
||
|
||
// Token 写操作限速器
|
||
export const tokenWriteLimiter = rateLimit({
|
||
windowMs: 1 * 60 * 1000, // 1分钟
|
||
limit: 512, // 每个token在1分钟内最多512次写操作
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "写操作请求过于频繁,请稍后再试",
|
||
keyGenerator: getRateLimitKey,
|
||
skipSuccessfulRequests: false,
|
||
skipFailedRequests: false,
|
||
});
|
||
|
||
// Token 删除操作限速器
|
||
export const tokenDeleteLimiter = rateLimit({
|
||
windowMs: 1 * 60 * 1000, // 1分钟
|
||
limit: 256, // 每个token在1分钟内最多256次删除操作
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "删除操作请求过于频繁,请稍后再试",
|
||
keyGenerator: getRateLimitKey,
|
||
skipSuccessfulRequests: false,
|
||
skipFailedRequests: false,
|
||
});
|
||
|
||
// Token 批量操作限速器
|
||
export const tokenBatchLimiter = rateLimit({
|
||
windowMs: 1 * 60 * 1000, // 1分钟
|
||
limit: 128, // 每个token在1分钟内最多128次批量操作
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "批量操作请求过于频繁,请稍后再试",
|
||
keyGenerator: getRateLimitKey,
|
||
skipSuccessfulRequests: false,
|
||
skipFailedRequests: false,
|
||
});
|
||
|
||
// 创建一个路由处理中间件,根据HTTP方法应用不同的限速器
|
||
export const methodBasedRateLimiter = (req, res, next) => {
|
||
// 检查是否是批量导入路由
|
||
if (req.method === "POST" && req.path.endsWith("/batch-import")) {
|
||
return batchLimiter(req, res, next);
|
||
} else if (req.method === "GET") {
|
||
// 读操作使用普通API限速
|
||
return apiLimiter(req, res, next);
|
||
} else if (
|
||
req.method === "POST" ||
|
||
req.method === "PUT" ||
|
||
req.method === "PATCH"
|
||
) {
|
||
// 写操作使用更严格的限速
|
||
return writeLimiter(req, res, next);
|
||
} else if (req.method === "DELETE") {
|
||
// 删除操作使用最严格的限速
|
||
return deleteLimiter(req, res, next);
|
||
}
|
||
// 其他方法使用API限速
|
||
return apiLimiter(req, res, next);
|
||
};
|
||
|
||
// Token 专用路由中间件:根据HTTP方法应用不同的Token限速器
|
||
export const tokenBasedRateLimiter = (req, res, next) => {
|
||
// 检查是否是批量导入路由
|
||
if (req.method === "POST" && (req.path.endsWith("/_batchimport") || req.path.endsWith("/batch-import"))) {
|
||
return tokenBatchLimiter(req, res, next);
|
||
} else if (req.method === "GET") {
|
||
// 读操作使用Token读限速
|
||
return tokenReadLimiter(req, res, next);
|
||
} else if (
|
||
req.method === "POST" ||
|
||
req.method === "PUT" ||
|
||
req.method === "PATCH"
|
||
) {
|
||
// 写操作使用Token写限速
|
||
return tokenWriteLimiter(req, res, next);
|
||
} else if (req.method === "DELETE") {
|
||
// 删除操作使用Token删除限速
|
||
return tokenDeleteLimiter(req, res, next);
|
||
}
|
||
// 其他方法使用Token读限速
|
||
return tokenReadLimiter(req, res, next);
|
||
};
|