文档目录
中间件管道

简介

本文件面向 DouPHP 框架的中间件管道,系统性说明请求处理管道的组织方式、中间件执行顺序、上下文传递机制,以及安全、认证、限流等关键中间件的实现。文档同时给出自定义中间件的开发指南、最佳实践与调试技巧,并通过流程图展示不同场景下的配置和使用模式。

项目结构

DouPHP 将中间件按“端”进行划分,便于在不同入口(后台 admin、前台 front、API)独立装配和管理:

  • 后台(admin):认证、权限、CSRF、安全头、工作区等
  • 前台(front):用户认证、CSRF、限流、安全头
  • API:用户认证、限流、安全头
  • 基础能力(core/foundation/middleware):提供抽象基类与统一接口,确保三端行为一致
graph TB
subgraph "核心基础设施"
A["抽象安全头中间件<br/>AbstractSecurityHeadersMiddleware"]
B["抽象用户认证中间件<br/>AbstractUserAuthMiddleware"]
C["抽象CSRF中间件<br/>AbstractCsrfMiddleware"]
D["抽象限流中间件<br/>AbstractThrottleMiddleware"]
end
subgraph "后台 Admin"
E["认证中间件<br/>AuthMiddleware"]
F["权限中间件<br/>PermissionMiddleware"]
G["CSRF中间件后台<br/>CsrfMiddleware"]
H["安全头中间件后台"]
end
subgraph "前台 Front"
I["用户认证中间件前台<br/>UserAuthMiddleware"]
J["CSRF中间件前台<br/>CsrfMiddleware"]
K["限流中间件前台"]
L["安全头中间件前台"]
end
subgraph "API"
M["用户认证中间件API<br/>UserAuthMiddleware"]
N["限流中间件API<br/>ThrottleMiddleware"]
O["安全头中间件API"]
end
A --> H
A --> L
A --> O
B --> I
B --> M
C --> G
C --> J
D --> N

核心组件

  • 抽象安全头中间件:在管道最前置下发基线安全响应头(如 X-Content-Type-Options、X-Frame-Options、Referrer-Policy、Permissions-Policy),并在 HTTPS 且开启时下发 HSTS。仅对命中路由生效。
  • 抽象用户认证中间件:承载通用鉴权骨架(路由段 → 策略决策 → 三态分支 + work 子策略),各端子类负责从请求中解析 token/session 并注入身份上下文。
  • 抽象 CSRF 中间件:封装令牌校验流程,各端子类定义令牌模型(静态令牌或一次性令牌)、豁免路由与失败处理。
  • 抽象限流中间件:基于 IP 与路由键进行配额控制,超限返回 429。

架构总览

请求进入后,先经过安全头中间件设置响应头;随后进入认证、权限、CSRF、限流等业务中间件链;最终到达控制器并返回响应。中间件以“洋葱模型”执行:进入阶段自上而下,返回阶段自下而上。

sequenceDiagram
participant Client as "客户端"
participant Pipe as "中间件管道"
participant Sec as "安全头中间件"
participant Auth as "认证中间件"
participant Perm as "权限中间件"
participant Csrf as "CSRF中间件"
Ctl as "控制器"
Client->>Pipe : "HTTP 请求"
Pipe->>Sec : "handle(next)"
Sec-->>Pipe : "设置安全响应头"
Pipe->>Auth : "handle(next)"
Auth-->>Pipe : "恢复/解析登录态并注入上下文"
Pipe->>Perm : "handle(next)"
Perm-->>Pipe : "校验模块访问权限"
Pipe->>Csrf : "handle(next)"
Csrf-->>Pipe : "校验表单令牌"
Pipe->>Ctl : "调用控制器"
Ctl-->>Pipe : "返回响应"
Pipe-->>Client : "带安全头的响应"

详细组件分析

安全中间件(安全响应头)

  • 职责:在管道最前置下发基线安全头;仅在 HTTPS 且配置开启时下发 HSTS;仅对命中路由生效。
  • 配置来源:读取 security.headers 配置项,决定是否下发具体头部。
  • 扩展点:三端薄壳子类继承基类即可复用相同行为。
flowchart TD
Start(["进入安全头中间件"]) --> ReadCfg["读取 security.headers 配置"]
ReadCfg --> CheckSent{"是否已发送响应头?"}
CheckSent -- "是" --> Skip["跳过设置"]
CheckSent -- "否" --> Apply["根据配置设置安全头"]
Apply --> Next["调用下一个中间件"]
Skip --> Next
Next --> End(["结束"])

认证中间件(后台)

  • 职责:从会话恢复管理员登录态;未登录则重定向到登录页;通过后放行管道。
  • 免登策略:通过路由级声明式豁免,不在中间件内硬编码名单。
  • 视图上下文:由工作区中间件负责注入全局变量。
sequenceDiagram
participant MW as "Admin 认证中间件"
participant Guard as "auth('admin')"
participant Next as "后续中间件/控制器"
MW->>Guard : "restoreFromSession(ip)"
alt 未恢复登录态
MW-->>Next : "抛出异常并重定向到登录页"
else 成功恢复
MW-->>Next : "继续执行管道"
end

权限中间件(后台)

  • 职责:检查当前管理员对目标模块/动作的访问权限;超级管理员直接放行;否则依据白名单判定。
  • 前置条件:依赖认证中间件已写入管理员信息。
flowchart TD
S(["进入权限中间件"]) --> GetUser["获取当前管理员信息"]
GetUser --> HasUser{"是否存在管理员?"}
HasUser -- "否" --> RedirectLogin["重定向到登录页"]
HasUser -- "是" --> GetRoute["读取路由模块/动作/ID"]
GetRoute --> CanAccess{"Gate.canAccess() 是否允许?"}
CanAccess -- "否" --> RedirectHome["重定向到管理首页"]
CanAccess -- "是" --> Next["放行到后续中间件/控制器"]

CSRF 中间件(后台)

  • 令牌模型:默认使用共享静态令牌 static_admin;特定匿名流程使用一次性令牌(如密码重置)。
  • GET 校验:部分带 token 的 GET 链接也参与校验(备份、导入、报表导出)。
  • 失败处理:抛出领域异常,由入口捕获后输出统一提示页。
flowchart TD
Start(["进入后台 CSRF 中间件"]) --> MapToken["根据路由映射令牌 ID"]
MapToken --> Validate{"令牌校验通过?"}
Validate -- "否" --> Reject["抛出领域异常并提示"]
Validate -- "是" --> Next["放行到后续中间件"]

认证中间件(前台)

  • 职责:通过 auth('front') 解析登录态并注入上下文;拒绝时根据请求类型返回 JSON 或直接重定向到登录页。
  • 特殊处理:XHR 请求携带 from=js 时返回 JSON 错误并附带跳转地址。
sequenceDiagram
participant MW as "Front 认证中间件"
participant Guard as "auth('front')"
participant Next as "后续中间件/控制器"
MW->>Guard : "resolveUserContext()"
alt 未解析到用户
MW-->>Next : "根据请求类型返回 JSON 或重定向到登录页"
else 解析成功
MW->>Guard : "hydrate(context)"
MW-->>Next : "继续执行管道"
end

认证中间件(API)

  • 职责:从 Authorization: Bearer &lt;token> 提取 token,交由 auth('api') 解析登录态;拒绝时返回 JSON 401/403。
  • 工作身份:支持 work 子策略,无工作身份时拒绝。
sequenceDiagram
participant MW as "API 认证中间件"
participant Guard as "auth('api')"
participant Next as "后续中间件/控制器"
MW->>MW : "读取 bearerToken()"
MW->>Guard : "resolveUserContext(token)"
alt 未解析到用户
MW-->>Next : "返回 401 未登录"
else 解析成功
MW->>Guard : "hydrate(context)"
MW->>MW : "检查工作身份"
alt 无工作身份
MW-->>Next : "返回 403 禁止"
else 有工作身份
MW-->>Next : "继续执行管道"
end
end

限流中间件(API)

  • 职责:对敏感与高频接口按 IP 限流;超限返回 429 并设置 Retry-After。
  • 配置方式:通过路由键映射配额(次数/时间窗口)。
flowchart TD
Start(["进入 API 限流中间件"]) --> Match["匹配路由键并获取配额"]
Match --> Check{"是否超过配额?"}
Check -- "是" --> Reject["返回 429 并设置 Retry-After"]
Check -- "否" --> Next["放行到后续中间件"]

CSRF 中间件(前台)

  • 令牌模型:会员使用静态令牌 static_user;匿名表单使用一次性令牌抗重放。
  • GET 校验:部分带 token 的 GET 链接也参与校验(取消预约、商家处理、余额扣款等)。
  • 失败处理:抛出领域异常并提示刷新/重新登录。
flowchart TD
Start(["进入前台 CSRF 中间件"]) --> MapOneTime{"是否一次性令牌路由?"}
MapOneTime -- "是" --> UseOneTime["使用一次性令牌"]
MapOneTime -- "否" --> UseStatic["使用静态令牌"]
UseOneTime --> Validate{"令牌校验通过?"}
UseStatic --> Validate
Validate -- "否" --> Reject["抛出领域异常并提示"]
Validate -- "是" --> Next["放行到后续中间件"]

依赖关系分析

  • 安全头中间件依赖配置中心读取 security.headers。
  • 认证中间件依赖各端 guard(auth('admin'|'front'|'api'))进行登录态恢复与注入。
  • 权限中间件依赖授权门控(AdminGate)进行模块访问判定。
  • CSRF 中间件依赖令牌服务(csrf())生成与校验。
  • 限流中间件依赖存储与计数逻辑(由抽象基类封装)。
graph LR
Sec["安全头中间件"] --> Cfg["配置中心"]
AuthA["后台认证中间件"] --> GuardA["auth('admin')"]
AuthF["前台认证中间件"] --> GuardF["auth('front')"]
AuthAPI["API认证中间件"] --> GuardAPI["auth('api')"]
Perm["权限中间件"] --> Gate["AdminGate"]
CsrfA["后台CSRF中间件"] --> TokenA["csrf()"]
CsrfF["前台CSRF中间件"] --> TokenF["csrf()"]
Throttle["API限流中间件"] --> Store["限流存储(抽象)"]

性能考虑

  • 安全头中间件置于管道最前,避免重复设置,减少响应头开销。
  • 认证中间件优先于业务逻辑,尽早拒绝无效请求,降低后端负载。
  • 限流中间件针对高频接口进行前置拦截,防止资源滥用。
  • CSRF 校验尽量在管道早期完成,避免不必要的控制器执行。
  • 建议将昂贵操作(如数据库查询、外部调用)放在中间件之后,以减少无效请求的处理成本。

故障排查指南

  • 安全头未生效:检查 security.headers 配置与是否已在 HTTPS 环境启用 HSTS;确认中间件位于管道前端。
  • 认证失败:确认对应端 guard 是否正确恢复/解析登录态;检查 token/session 是否有效。
  • 权限被拒:确认管理员角色与模块/动作白名单;检查路由模块与动作参数是否正确。
  • CSRF 校验失败:核对令牌模型(静态/一次性)与路由映射;检查 GET 链接是否包含正确 token。
  • 限流触发:查看接口配额配置与当前 IP 访问频率;必要时调整窗口与阈值。

结论

DouPHP 的中间件管道通过抽象基类与端侧薄壳实现了高内聚、低耦合的请求处理体系。安全头、认证、权限、CSRF、限流等中间件各司其职,组合灵活,易于扩展。遵循本文的配置与使用模式,可在不同场景下快速搭建稳定可靠的请求处理链路。

附录:配置与使用模式

  • 安全头配置:在 security.headers 中启用所需的安全头;HSTS 需在 HTTPS 且显式开启。
  • 认证配置:为各端配置对应的 guard,并确保能正确解析 token/session。
  • CSRF 配置:按需选择静态令牌或一次性令牌;对需要 GET 校验的路由加入列表。
  • 限流配置:为敏感接口设定合理的 max/window;监控 429 比例以调优。
  • 自定义中间件:实现 MiddlewareInterface,遵循“进入阶段处理、返回阶段收尾”的模式;优先使用抽象基类减少重复代码。
添加日期:2026-10-05