# F. 中间件执行顺序 :::tip 概述 本页展示请求在框架中的完整中间件执行流程,包括全局中间件和应用中间件的执行顺序,帮助开发者理解请求处理链路。 ::: ## 执行流程图 ```text 请求进入 │ ▼ ┌────────────────┐ │ProxyMiddleware │ 全局中间件(最先执行) │ │ 从代理头提取真实客户端 IP └──────┬─────────┘ │ ▼ ┌──────────────┐ │CorsMiddleware│ 全局中间件 │ │ 处理 OPTIONS 预检 + 跨域响应头 └──────┬───────┘ │ ▼ ┌──────────────┐ 401 │AuthMiddleware│──────────► 未认证(Token 缺失/无效/过期) │ │ 403 │ JWT认证 │──────────► 无权限 │ 权限校验 │ └──────┬───────┘ │ 注入 userInfo ▼ ┌──────────────┐ 403 │TenantMiddleware│──────────► 租户异常(禁用/过期) │ │ │ 租户上下文 │ └──────┬───────┘ │ 注入 tenantId, tenantInfo ▼ ┌──────────────┐ 403 │DemoMiddleware│──────────► 演示环境禁止写操作 └──────┬───────┘ │ ▼ ┌──────────────┐ │ LogMiddleware│ 记录操作日志(写操作始终记录) └──────┬───────┘ │ ▼ ┌──────────────┐ │ 控制器方法 │ └──────────────┘ ``` ## 中间件职责 | 中间件 | 类型 | 职责 | 配置 | |--------|------|------|------| | ProxyMiddleware | 全局 | 代理头解析,提取真实客户端 IP | .env → `[API]` PROXY_IPS | | CorsMiddleware | 全局 | 跨域处理 | config/cors.php | | AuthMiddleware | 路由级 | JWT 认证 + 权限校验 | config/middleware.php → auth_except | | TenantMiddleware | 路由级 | 租户上下文注入 | 内置排除列表 | | DemoMiddleware | 路由级 | 演示环境拦截 | .env → [APP] DEMO | | LogMiddleware | 路由级 | 操作日志记录 | config/middleware.php → log_except | ## 排除配置 ```php // config/middleware.php return [ 'auth_except' => [ 'login', 'captcha', 'oauth2/token', 'oauth2/check/token', ], 'log_except' => [ 'login', 'logout', 'captcha', 'oauth2', ], ]; ``` ## 注入内容 | 中间件 | 注入字段 | 说明 | |--------|---------|------| | ProxyMiddleware | `$_SERVER['REMOTE_ADDR']` | 覆盖为真实客户端 IP | | AuthMiddleware | `$request->userInfo` | 用户信息(uid, username, type 等) | | TenantMiddleware | `$request->tenantId` | 租户 ID(0=超级管理员) | | TenantMiddleware | `$request->isSuperAdmin` | 是否超级管理员 | | TenantMiddleware | `$request->tenantInfo` | 租户信息对象 | ## ProxyMiddleware 详解 当项目部署在 CDN / 负载均衡 / Nginx 反向代理后面时,PHP 的 `REMOTE_ADDR` 是代理服务器的 IP(通常是 `127.0.0.1`),真实客户端 IP 由代理通过 `X-Forwarded-For` / `X-Real-IP` 请求头传递。 ### 工作原理 ```text 客户端(真实IP) → CDN/代理 → Nginx → PHP-FPM ↓ 设置头 X-Forwarded-For: 真实IP, 代理IP X-Real-IP: 真实IP ``` 1. 检查 `REMOTE_ADDR` 是否在受信代理列表(`.env` → `PROXY_IPS`) 2. 如果是,从 `X-Real-IP` 或 `X-Forwarded-For` 头提取真实 IP 3. 覆盖 `$_SERVER['REMOTE_ADDR']`,后续 `request()->ip()` 返回真实 IP ### 配置 ```ini # .env [API] 段 # 受信代理 IP(逗号分隔,支持 CIDR 网段) # 未配置时默认信任 127.0.0.1 和 ::1 PROXY_IPS = 127.0.0.1,::1,101.226.0.0/15,180.101.0.0/16 ```