mirror of
https://github.com/ZeroCatDev/ClassworksKV.git
synced 2025-12-07 13:03:09 +00:00
- Added refresh token support in the account model with new fields: refreshToken, refreshTokenExpiry, and tokenVersion. - Created a new token management utility (utils/tokenManager.js) for generating and verifying access and refresh tokens. - Updated JWT utility (utils/jwt.js) to maintain backward compatibility while introducing new token generation methods. - Enhanced middleware for JWT authentication to support new token types and automatic token refreshing. - Expanded API endpoints in routes/accounts.js to include refresh token functionality, logout options, and token info retrieval. - Introduced automatic token refresh mechanism in the front-end integration examples. - Comprehensive migration checklist and documentation for the new refresh token system. - Added database migration script to accommodate new fields in the Account table.
121 lines
3.6 KiB
JavaScript
121 lines
3.6 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)}`;
|
||
};
|
||
|
||
// 纯基于Token的keyGenerator,用于KV Token专用路由
|
||
// 这个函数假设token已经通过中间件设置在req对象上
|
||
export const getTokenOnlyKey = (req) => {
|
||
// 尝试从多个位置获取token
|
||
const token =
|
||
req.locals?.token || // 如果token被设置在req.locals中
|
||
req.res?.locals?.token || // 如果token在res.locals中
|
||
extractToken(req); // 从headers/query/body提取
|
||
|
||
if (!token) {
|
||
// 如果没有token,返回一个特殊键用于统一限制
|
||
return "no-token";
|
||
}
|
||
return `token:${token}`;
|
||
};
|
||
|
||
// 创建一个中间件来将res.locals.token复制到req.locals.token,以便限速器使用
|
||
export const prepareTokenForRateLimit = (req, res, next) => {
|
||
if (res.locals.token) {
|
||
req.locals = req.locals || {};
|
||
req.locals.token = res.locals.token;
|
||
}
|
||
next();
|
||
};
|
||
|
||
|
||
|
||
// 认证相关路由限速器(防止暴力破解)
|
||
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, // 失败的认证计入限制
|
||
});
|
||
|
||
// === Token 专用限速器(更宽松的限制,纯基于Token) ===
|
||
|
||
// Token 读操作限速器
|
||
export const tokenReadLimiter = rateLimit({
|
||
windowMs: 1 * 60 * 1000, // 1分钟
|
||
limit: 1024, // 每个token在1分钟内最多1024次读操作
|
||
standardHeaders: "draft-7",
|
||
legacyHeaders: false,
|
||
message: "读操作请求过于频繁,请稍后再试",
|
||
keyGenerator: getTokenOnlyKey,
|
||
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: getTokenOnlyKey,
|
||
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: getTokenOnlyKey,
|
||
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: getTokenOnlyKey,
|
||
skipSuccessfulRequests: false,
|
||
skipFailedRequests: false,
|
||
});
|