文档目录
自定义中间件开发

简介

本指南面向 DouPHP 框架开发者,系统说明如何编写、注册与使用自定义中间件。内容涵盖:

  • 中间件类结构与接口规范(handle 生命周期)
  • 基于抽象基类的鉴权中间件实现模式
  • 不同应用(前台 front、API、后台 admin)的中间件注册与配置方式
  • 从简单日志到复杂业务逻辑的完整示例思路
  • 测试、调试技巧与性能优化建议
  • 错误处理、异常捕获与响应修改最佳实践
  • 中间件与控制器、服务的交互方式

项目结构

DouPHP 将中间件按“端”组织,便于在不同入口独立装配:

  • 前台 front/middleware:用户认证、限流、安全头等
  • API api/middleware:API 鉴权、限流、安全头等
  • 后台 admin/middleware:管理员认证、权限、安全头等
  • 核心基础 core/foundation/middleware:统一接口与通用基类
graph TB
subgraph "核心"
MI["MiddlewareInterface"]
AUA["AbstractUserAuthMiddleware"]
ASH["AbstractSecurityHeadersMiddleware"]
end
subgraph "前台"
FUA["front/middleware/UserAuthMiddleware"]
FTH["front/middleware/ThrottleMiddleware"]
FSH["front/middleware/SecurityHeadersMiddleware"]
FCsrf["front/middleware/CsrfMiddleware"]
end
subgraph "API"
AUAi["api/middleware/UserAuthMiddleware"]
ATH["api/middleware/ThrottleMiddleware"]
ASHi["api/middleware/SecurityHeadersMiddleware"]
end
subgraph "后台"
AMW["admin/middleware/AuthMiddleware"]
PMW["admin/middleware/PermissionMiddleware"]
CSF["admin/middleware/CsrfMiddleware"]
SHM["admin/middleware/SecurityHeadersMiddleware"]
end
MI --> AUA
MI --> ASH
AUA --> FUA
AUA --> AUAi
ASH --> FSH
ASH --> ASHi
MI --> AMW
MI --> PMW
MI --> CSF
MI --> SHM

核心组件

  • 中间件接口 MiddlewareInterface:定义 handle($next) 生命周期方法,要求放行时 return $next(),不得丢弃下游返回值。
  • 用户鉴权基类 AbstractUserAuthMiddleware:模板方法封装“路由段解析 → 策略决策 → public/optional/required 分支 → 身份注入 → work 子策略 → 放行”,子类仅需实现 guard 选择、配置文件路径、拒绝响应等差异点。
  • 安全头基类 AbstractSecurityHeadersMiddleware:在管道最前置下发安全响应头(X-Content-Type-Options、X-Frame-Options、Referrer-Policy、Permissions-Policy;HSTS 条件下发)。

架构总览

请求进入 Dispatcher,经中间件管道执行后到达控制器。各端通过 init/middleware.php 声明鉴权模式,结合路由级覆盖,决定是否需要登录或工作端身份。

sequenceDiagram
participant C as "客户端"
participant D as "分发器 Dispatcher"
participant P as "中间件管道"
participant M as "具体中间件"
participant R as "控制器动作"
C->>D : "HTTP 请求"
D->>P : "构建并执行管道"
P->>M : "调用 handle(next)"
M->>M : "校验/记录/设置上下文"
M-->>P : "return $next()"
P->>R : "调用控制器"
R-->>P : "返回 Response/数据"
P-->>C : "输出响应"

详细组件分析

中间件接口与生命周期

  • 接口方法 handle($next):负责在合适时机调用下一个处理器或短路返回。
  • 关键契约:必须 return $next(),否则控制器响应会被吞掉。

用户鉴权中间件基类(模板方法)

  • 职责:根据路由段与配置表决定 public/optional/required,必要时注入用户上下文,并在 required + 无 work 身份时拒绝。
  • 扩展点:子类需实现 configFile()、resolveContext()、inject()、hasWorkIdentity()、rejectUnauthenticated()、rejectForbidden()。
  • 路由级覆盖:可通过 setRouteParameters([mode]) 强制指定鉴权模式。
flowchart TD
Start(["进入 handle"]) --> Parse["解析路由段 module/sub/action"]
Parse --> Decide{"策略决策<br/>public/optional/required"}
Decide --> |public| Next1["直接放行"]
Decide --> |optional|required| Resolve["解析用户上下文 resolveContext()"]
Resolve --> Ok{"是否登录 ok=true?"}
Ok --> |否| ModeCheck{"模式=required?"}
ModeCheck --> |是| Reject["rejectUnauthenticated()"]
ModeCheck --> |否| Next2["放行匿名"]
Ok --> |是| Inject["注入上下文 inject()"]
Inject --> Work{"work_required 且无工作身份?"}
Work --> |是| Forbid["rejectForbidden()"]
Work --> |否| Next3["放行"]

前台用户认证中间件

  • 继承自抽象基类,使用 auth('front') guard,拒绝时支持跳转登录页或 JSON 401(XHR from=js)。
  • 配置文件路径:FRONT_PATH . 'init/middleware.php'。

API 用户认证中间件

  • 继承自抽象基类,使用 auth('api') guard,从 Authorization: Bearer 提取 token 解析登录态。
  • 拒绝时直接发送 JSON 错误(401/403)并 exit。
  • 配置文件路径:API_PATH . 'init/middleware.php'。

后台认证中间件

  • 实现 MiddlewareInterface,通过 auth('admin')->restoreFromSession(ip) 恢复登录态。
  • 未登录抛出 HttpResponseException 重定向至登录页;已登录则放行。

安全响应头中间件

  • 基类在管道最前置下发安全头,仅对命中路由生效。
  • 三端薄壳子类可复用该行为。

鉴权模式配置(单中间件多模式)

  • 前台与 API 均通过 init/middleware.php 中的 auth_modes 与 work_required 声明模块级鉴权级别与工作端要求。
  • 支持 module / module/action / module/sub / module/sub/action 多级键匹配。
  • 新增模块必须在配置中显式登记,避免静默公开。

依赖关系分析

  • 中间件依赖 request()/auth() 等全局辅助获取请求与守卫。
  • 鉴权中间件依赖 UserAuthPolicy(由基类内部使用)进行策略决策。
  • 分发器 Dispatcher 负责在管道中实例化控制器并执行,不关心中间件细节。
classDiagram
class MiddlewareInterface {
+handle(next) mixed
}
class AbstractUserAuthMiddleware {
-authModes array
-workRequired array
-routeModeOverride string?
+setRouteParameters(params) void
+handle(next) mixed
#configFile() string
#resolveContext() array
#inject(context) void
#hasWorkIdentity() bool
#rejectUnauthenticated() void
#rejectForbidden() void
}
class FrontUserAuthMiddleware
class ApiUserAuthMiddleware
class AdminAuthMiddleware
class Dispatcher {
+run(plan, container) mixed
}
MiddlewareInterface <|.. AbstractUserAuthMiddleware
AbstractUserAuthMiddleware <|-- FrontUserAuthMiddleware
AbstractUserAuthMiddleware <|-- ApiUserAuthMiddleware
MiddlewareInterface <|.. AdminAuthMiddleware
Dispatcher ..> MiddlewareInterface : "管道执行"

性能考虑

  • 中间件应轻量:避免在 handle 中进行重型 I/O;将耗时操作下沉到服务层或异步任务。
  • 尽早短路:鉴权失败立即返回,减少后续中间件与控制器开销。
  • 缓存友好:对只读上下文(如用户信息)尽量复用 Guard 缓存,避免重复查询。
  • 安全头仅在命中路由下发,减少不必要开销。
  • 合理拆分中间件:单一职责,便于按需启用与测试。

故障排查指南

  • 响应被吞掉:检查是否忘记 return $next(),或捕获了下游响应却未返回。
  • 鉴权误拦截:核对 init/middleware.php 中对应模块/动作的 auth_modes 是否正确;必要时使用路由级覆盖。
  • 工作端权限不足:确认 work_required 列表是否包含当前模块;检查 hasWorkIdentity 判定逻辑。
  • 前端 XHR 登录超时:前台 rejectUnauthenticated 会返回带 jump_url 的 JSON;确保前端能处理该字段并重定向。
  • 安全头未生效:确认请求命中路由且在 headers_sent() 之前;HTTPS 下 HSTS 需要显式开启。

结论

DouPHP 的中间件体系以统一接口与可复用的鉴权基类为核心,配合各端独立的鉴权配置,实现了高内聚、低耦合的可插拔横切能力。遵循 handle 契约、合理使用公共基类、在 init/middleware.php 中显式声明鉴权模式,即可快速构建稳定可靠的自定义中间件。

附录

开发步骤清单

  • 新建中间件类,实现 MiddlewareInterface 或继承 AbstractUserAuthMiddleware/AbstractSecurityHeadersMiddleware。
  • 在 handle 中完成前置处理,务必 return $next() 放行。
  • 如需鉴权:
    • 在前台或 API 端创建中间件,实现配置文件路径、上下文解析、注入与拒绝逻辑。
    • 在对应 init/middleware.php 的 auth_modes 中登记模块/动作的鉴权级别。
  • 在路由或管道中注册中间件(由框架调度),并通过路由级参数覆盖鉴权模式。
  • 编写单元测试:模拟请求、断言响应状态码与头部、验证是否调用 $next()。
  • 调试技巧:
    • 在 handle 前后记录请求 ID、耗时、关键上下文。
    • 使用浏览器网络面板或 curl 查看响应头与状态码。
    • 针对 XHR 场景检查 from=js 分支。
添加日期:2026-10-05