文档目录
速率限制与防刷

简介

本文件面向 DouPHP 的“速率限制与防刷”能力,系统性说明以下方面:

  • IP 级限流:基于来源 IP 的请求频率控制与并发连接限制思路。
  • 用户级限流:基于用户 ID 的访问频率控制与资源使用配额。
  • 接口级限流:针对敏感 API 接口的差异化限流策略。
  • 防刷机制:验证码集成、行为分析与异常检测。
  • 配置选项与监控告警:如何配置限流存储、默认策略,以及如何通过日志与审计进行观测与告警。

项目结构

DouPHP 在前后端分别提供定向限流中间件,统一继承自抽象基类,并通过文件型计数器存储实现轻量级窗口计数;登录失败场景采用数据库审计表做 IP 级限流;验证码由独立控制器下发与校验。

graph TB
A["请求进入"] --> B["API 中间件<br/>api/middleware/ThrottleMiddleware.php"]
A --> C["前台中间件<br/>front/middleware/ThrottleMiddleware.php"]
B --> D["抽象基类<br/>AbstractThrottleMiddleware.php"]
C --> D
D --> E["限流存储<br/>ThrottleStore.php"]
B --> F["API 验证码<br/>api/controller/captcha/CaptchaController.php"]
C --> G["前台验证码/核验<br/>front/controller/user/VerificationController.php"]
subgraph "登录失败限流"
H["前台认证门面<br/>front/facade/Auth.php"]
I["用户服务 IP 限流<br/>UserAuthService.php"]
end
H --> I

核心组件

  • 抽象限流中间件:定义通用流程(解析路由键、计算配额、调用存储计数、超限拒绝)。
  • API 限流中间件:对登录、注册、短信验证码、公共匿名写、防伪查询、LLM 成本端点等按 IP 限流。
  • 前台限流中间件:对登录、注册、找回密码、短信验证码、留言、咨询、订阅、聊天等按 IP 限流。
  • 限流存储:基于文件的轻量计数器,支持窗口重置、过期清理。
  • 登录失败 IP 限流:基于 user_log 审计表的窗口内失败次数统计。
  • 验证码:API 与后台各自下发 token/图形验证码,前端提交时校验。

架构总览

下图展示一次受保护的 API 请求从进入、限流判定到返回的完整链路,并标注关键文件位置。

sequenceDiagram
participant Client as "客户端"
participant API as "API 入口"
participant Throttle as "API 限流中间件"
participant Base as "抽象限流基类"
participant Store as "限流存储(文件)"
participant Controller as "业务控制器"
Client->>API : HTTP 请求
API->>Throttle : 进入中间件
Throttle->>Base : 解析 module.action.ip 键
Base->>Store : hit(key, window)
Store-->>Base : 返回当前窗口计数
alt 超过配额
Base->>Throttle : reject(retryAfter)
Throttle-->>Client : 429 + Retry-After
else 未超限
Base->>Controller : 放行
Controller-->>Client : 正常响应
end

详细组件分析

组件一:IP 级限流(接口维度)

  • 适用场景:登录、注册、手机号登录、找回密码、短信验证码下发、公共匿名写(留言/咨询/邮件订阅)、防伪查询、LLM 成本端点等。
  • 策略要点:
    • 以 module.action.ip 为限流键,避免跨模块/动作共享配额。
    • 每个接口可配置独立的 max/window,体现差异化保护。
    • 超限返回 429,并附带 Retry-After 头,便于客户端退避重试。
  • 存储实现:文件后端 JSON 记录 count/reset,窗口到期自动重置,支持机会式清理过期文件。
flowchart TD
Start(["请求进入"]) --> Key["生成限流键<br/>module.action.ip"]
Key --> Check{"是否命中配额?"}
Check -- 否 --> Allow["放行至控制器"]
Check -- 是 --> Reject["返回 429<br/>设置 Retry-After"]
Allow --> End(["结束"])
Reject --> End

组件二:登录失败 IP 限流(用户安全维度)

  • 触发点:前台登录流程中,先检查当前 IP 是否在限流期。
  • 实现方式:统计 user_log 表中指定时间窗口内该 IP 的 LOGIN_FAIL 次数,达到阈值则拒绝后续尝试。
  • 联动:结合账号锁定、验证码有效性等前置校验,形成多层防护。
sequenceDiagram
participant U as "用户"
participant Auth as "前台认证门面"
participant Svc as "用户服务(IP限流)"
U->>Auth : 提交登录
Auth->>Svc : ipRateLimit(ip, limit, window)
Svc-->>Auth : true/false
alt 已限流
Auth-->>U : 提示“IP 限流”
else 未限流
Auth->>Auth : 继续验证码/账号锁定等校验
Auth-->>U : 登录结果
end

组件三:验证码集成(防刷关键一环)

  • API 侧:
    • 颁发验证码表单 token 对(captcha_token/storage_captcha_token),用于后续发送验证码时的校验。
    • 发送验证码接口受限流中间件保护,防止短信轰炸。
  • 后台侧:
    • 下发图形验证码 PNG,登录流程强制校验。
  • 前台侧:
    • 提供验证码核验页面与相关子控制器,配合业务表单完成人机验证。
sequenceDiagram
participant FE as "前端"
participant API as "API 验证码控制器"
participant SVC as "注册服务(令牌)"
participant CAP as "验证码服务"
FE->>API : 获取验证码 token
API->>SVC : createApiVerificationToken()
SVC-->>API : {captcha_token, storage_captcha_token}
API-->>FE : 返回 token 对
FE->>API : 提交验证码(含 token)
API->>CAP : sendCaptcha(...)
CAP-->>API : {code,msg,verification?}
API-->>FE : 成功或错误响应

组件四:接口级差异化限流策略

  • API 端重点保护:
    • 登录/注册/手机登录/找回密码:严格限制,防止暴力破解与批量注册。
    • 短信验证码下发:严格限制,防止短信轰炸。
    • 公共匿名写(留言/咨询/邮件订阅):适度限制,降低滥用风险。
    • 防伪查询:放宽单次扫描但收敛批量枚举。
    • LLM 成本端点:限制流式输出与会话创建,控制成本。
  • 前台端重点保护:
    • 登录/注册/找回密码/短信验证码:同 API 端策略。
    • 公共表单(留言/咨询/订阅):适度限制。
    • 聊天相关(流式/新建会话):控制资源消耗。

组件五:用户级限流与资源配额(设计建议)

  • 现状说明:
    • 当前代码实现了“登录失败 IP 限流”,以及“接口级 IP 限流”。
    • 未发现现成的“按用户 ID 的访问频率控制/资源配额”的通用实现。
  • 建议方案(概念性):
    • 在现有 AbstractThrottleMiddleware 基础上扩展 resolveKey,将 userId 纳入限流键(如 module.action.userId)。
    • 对需要配额的业务(如 AI 调用、导出、下载)增加“每日/每小时配额”的计数器,并在业务层拦截超额请求。
    • 结合用户等级/套餐,动态调整配额上限。
  • 注意:本节为设计建议,非现有代码实现。

组件六:行为分析与异常检测(设计建议)

  • 现状说明:
    • 系统通过登录失败审计日志(user_log)记录失败原因,可用于事后分析。
    • 未发现内置的行为分析引擎或实时异常检测模块。
  • 建议方案(概念性):
    • 基于审计日志聚合指标:单位时间内失败率、验证码失败率、429 比例等。
    • 设定阈值触发告警:如单 IP 短时间大量失败、单用户高频调用等。
    • 接入外部风控:设备指纹、地理位置异常、代理/VPN 识别等。
  • 注意:本节为设计建议,非现有代码实现。

依赖关系分析

  • 中间件依赖抽象基类,统一限流流程。
  • 抽象基类依赖配置项 security.throttle.store 确定存储路径。
  • 限流存储使用文件系统,并发写入通过锁保证一致性。
  • 登录失败限流依赖 user_log 审计表。
  • 验证码控制器依赖注册服务生成 token,并调用验证码服务发送验证码。
classDiagram
class AbstractThrottleMiddleware {
+throttleFor(module, action, sub) array|null
+reject(retryAfter) void
+resolveKey(module, action, sub, ip) string
+store() ThrottleStore
}
class ApiThrottleMiddleware {
+throttleFor(module, action, sub) array|null
+reject(retryAfter) void
}
class FrontThrottleMiddleware {
+throttleFor(module, action, sub) array|null
+reject(retryAfter) void
}
class ThrottleStore {
+hit(key, window) int
+tooMany(key, max, window) bool
+availableIn(key) int
+clear(key) void
+purgeExpired() void
}
class CaptchaController_API
class CaptchaController_Admin
class UserAuthService {
+ipRateLimit(ip, limit, window) bool
}
ApiThrottleMiddleware --|> AbstractThrottleMiddleware
FrontThrottleMiddleware --|> AbstractThrottleMiddleware
AbstractThrottleMiddleware --> ThrottleStore : "使用"
CaptchaController_API --> ThrottleStore : "间接(被中间件保护)"
CaptchaController_Admin --> ThrottleStore : "间接(被中间件保护)"
UserAuthService --> ThrottleStore : "不直接依赖(使用DB审计)"

性能考量

  • 文件存储适合单机或小规模部署;高并发或多实例需考虑分布式缓存(如 Redis)替换 ThrottleStore。
  • 窗口计数每次请求都会读写文件,需注意磁盘 IO;可通过合并写入、异步清理优化。
  • 登录失败限流基于数据库查询,应确保 user_log 索引合理(ip、action、created_at)。
  • 验证码下发属于外部服务调用,需加超时与重试策略,避免阻塞主流程。

故障排查指南

  • 429 频繁出现:
    • 检查对应路由的 throttleFor 配额是否过严。
    • 查看 ThrottleStore 目录下对应 key 的 JSON 文件,确认窗口与计数。
  • 登录失败提示“IP 限流”:
    • 检查 user_log 中该 IP 的 LOGIN_FAIL 记录数量与时间窗口。
    • 核对前端是否重复提交或脚本循环请求。
  • 验证码无效:
    • 确认前端是否正确获取并提交 captcha_token/storage_captcha_token。
    • 检查验证码服务返回码与消息。

结论

DouPHP 已具备完善的“接口级 IP 限流”与“登录失败 IP 限流”能力,并通过验证码机制强化防刷。对于“用户级限流”和“行为分析/异常检测”,当前仓库未见现成实现,可按本文建议扩展。生产环境建议结合部署拓扑(反向代理、多实例)选择合适的限流存储与监控告警方案。

附录:配置与监控告警建议

  • 配置项
    • 限流存储目录:security.throttle.store,默认位于 STORAGE_PATH . 'cache/throttle/'。
    • 全局默认限流:security.throttle.default,null 表示仅对敏感端点限流。
    • 可信代理与 Host:根据部署环境配置 trusted_proxies/trusted_hosts,确保 IP 可信。
  • 监控与告警
    • 利用登录失败审计日志(user_log)统计失败率、IP 集中度。
    • 对 429 响应比例、验证码失败率、短信下发量等指标建立看板与告警。
    • 定期清理 ThrottleStore 过期文件,避免磁盘膨胀。
添加日期:2026-10-05