签入版本
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# F. 中间件执行顺序
|
||||
|
||||
:::tip 概述
|
||||
本页展示请求在框架中的完整中间件执行流程,包括全局中间件和应用中间件的执行顺序,帮助开发者理解请求处理链路。
|
||||
本页展示请求在框架中的完整中间件执行流程,包括全局中间件和路由级中间件的执行顺序,帮助开发者理解请求处理链路。注册位置:`bootstrap/app.php`(别名 + API 组)与 `routes/api.php`(路由组)。
|
||||
:::
|
||||
|
||||
## 执行流程图
|
||||
@@ -11,39 +11,48 @@
|
||||
│
|
||||
▼
|
||||
┌────────────────┐
|
||||
│ProxyMiddleware │ 全局中间件(最先执行)
|
||||
│ProxyMiddleware │ API 组前置(最先执行)
|
||||
│ │ 从代理头提取真实客户端 IP
|
||||
└──────┬─────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│CorsMiddleware│ 全局中间件
|
||||
│ Cors │ API 组前置
|
||||
│ │ 处理 OPTIONS 预检 + 跨域响应头
|
||||
└──────┬───────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐ 401
|
||||
│AuthMiddleware│──────────► 未认证(Token 缺失/无效/过期)
|
||||
│ │ 403
|
||||
│ JWT认证 │──────────► 无权限
|
||||
│ 权限校验 │
|
||||
└──────┬───────┘
|
||||
│ 注入 userInfo
|
||||
▼
|
||||
┌──────────────┐ 403
|
||||
│TenantMiddleware│──────────► 租户异常(禁用/过期)
|
||||
│ │
|
||||
│ 租户上下文 │
|
||||
└──────┬───────┘
|
||||
│ 注入 tenantId, tenantInfo
|
||||
▼
|
||||
┌──────────────┐ 403
|
||||
│DemoMiddleware│──────────► 演示环境禁止写操作
|
||||
┌──────────────┐
|
||||
│ForceJson │ API 组前置
|
||||
│Response │ 强制返回 JSON 响应头
|
||||
└──────┬───────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐ 401
|
||||
│Authenticate │──────────► 未认证(Token 缺失/无效/过期)
|
||||
│ (auth.jwt) │ 403
|
||||
│ JWT认证 │──────────► 无权限
|
||||
│ 权限校验 │
|
||||
└──────┬───────┘
|
||||
│ 注入 userInfo(attributes)
|
||||
▼
|
||||
┌──────────────┐ 403
|
||||
│ResolveTenant │──────────► 租户异常(禁用/过期)
|
||||
│ (tenant) │
|
||||
│ 租户上下文 │
|
||||
└──────┬───────┘
|
||||
│ 注入 tenantId / isSuperAdmin / tenantInfo
|
||||
▼
|
||||
┌──────────────┐ 403
|
||||
│ demo │──────────► 演示模式下写操作被拦截
|
||||
│ (demo 别名) │
|
||||
│ 演示模式拦截 │
|
||||
└──────┬───────┘
|
||||
│ 放行:非演示模式 / GET / 有 #[DemoAllow]
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ LogMiddleware│ 记录操作日志(写操作始终记录)
|
||||
│ LogOperation │ 记录操作日志(terminable,响应后写入)
|
||||
│(log.operation)│ 写操作始终记录
|
||||
└──────┬───────┘
|
||||
│
|
||||
▼
|
||||
@@ -52,46 +61,53 @@
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
:::info 两种挂载方式
|
||||
- **API 组前置**(`bootstrap/app.php` → `$middleware->api(prepend:)`):Proxy → Cors → ForceJson,对全部 `/api` 请求生效
|
||||
- **路由组**(`routes/api.php` → `Route::middleware([...])->group(...)`):`auth.jwt` → `tenant` → `demo` → `log.operation`,仅认证接口组生效;登录、验证码、令牌刷新等公开接口定义在组外,天然免认证
|
||||
:::
|
||||
|
||||
## 中间件职责
|
||||
|
||||
| 中间件 | 类型 | 职责 | 配置 |
|
||||
|--------|------|------|------|
|
||||
| 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 |
|
||||
| ProxyMiddleware | API 组前置 | 代理头解析,提取真实客户端 IP | `.env` → `TRUSTED_PROXIES` |
|
||||
| Cors | API 组前置 | 跨域处理(OPTIONS 预检 + 响应头) | `config/cors.php` → `CORS_ALLOW_ORIGIN` |
|
||||
| ForceJsonResponse | API 组前置 | 强制 `Content-Type: application/json` | — |
|
||||
| Authenticate | 路由组(别名 `auth.jwt`) | JWT 认证 + 权限校验(`#[Permission]` 注解) | `config/middleware.php` → `auth_except` |
|
||||
| ResolveTenant | 路由组(别名 `tenant`) | 租户上下文注入与校验 | 超管(uid=1)跳过校验 |
|
||||
| LogOperation | 路由组(别名 `log.operation`) | 操作日志记录(terminable,响应后落库) | `config/middleware.php` → `log_except` |
|
||||
| DemoMiddleware | 路由组(别名 `demo`,tenant 与 log.operation 之间) | 演示模式拦截写操作(无 `#[DemoAllow]` 的写操作返回 403) | `config('app.demo_mode')` |
|
||||
|
||||
## 排除配置
|
||||
|
||||
```php
|
||||
// config/middleware.php
|
||||
return [
|
||||
// Authenticate::handle() 命中时跳过 JWT 解析与权限校验(公开接口定义在路由组外,此为兜底)
|
||||
'auth_except' => [
|
||||
'login',
|
||||
'captcha',
|
||||
'oauth2/token',
|
||||
'oauth2/check/token',
|
||||
'refresh',
|
||||
],
|
||||
// LogOperation::handle() 命中时不写入 OperationLog
|
||||
// 登录/登出由 LoginLog 单独记录
|
||||
'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 | `$_SERVER['REMOTE_ADDR']` | `request()->ip()` | 覆盖为真实客户端 IP |
|
||||
| Authenticate | `userInfo` | `$request->attributes->get('userInfo')` | 解码后的 JWT 载荷(uid、username 等) |
|
||||
| ResolveTenant | `tenantId` | `$request->attributes->get('tenantId')` | 租户 ID(0=平台用户) |
|
||||
| ResolveTenant | `isSuperAdmin` | `$request->attributes->get('isSuperAdmin')` | 是否超级管理员(uid=1) |
|
||||
| ResolveTenant | `tenantInfo` | `$request->attributes->get('tenantInfo')` | 非平台用户时注入租户模型实例 |
|
||||
|
||||
## ProxyMiddleware 详解
|
||||
|
||||
@@ -106,15 +122,15 @@ return [
|
||||
X-Real-IP: 真实IP
|
||||
```
|
||||
|
||||
1. 检查 `REMOTE_ADDR` 是否在受信代理列表(`.env` → `PROXY_IPS`)
|
||||
1. 检查 `REMOTE_ADDR` 是否在受信代理列表(`.env` → `TRUSTED_PROXIES`,支持 CIDR 网段)
|
||||
2. 如果是,从 `X-Real-IP` 或 `X-Forwarded-For` 头提取真实 IP
|
||||
3. 覆盖 `$_SERVER['REMOTE_ADDR']`,后续 `request()->ip()` 返回真实 IP
|
||||
3. 覆盖 `$_SERVER['REMOTE_ADDR']`,后续 `request()->ip()` 与 `get_client_ip()` 返回真实 IP
|
||||
|
||||
### 配置
|
||||
|
||||
```ini
|
||||
# .env [API] 段
|
||||
# .env
|
||||
# 受信代理 IP(逗号分隔,支持 CIDR 网段)
|
||||
# 未配置时默认信任 127.0.0.1 和 ::1
|
||||
PROXY_IPS = 127.0.0.1,::1,101.226.0.0/15,180.101.0.0/16
|
||||
```
|
||||
TRUSTED_PROXIES=127.0.0.1,::1,101.226.0.0/15,180.101.0.0/16
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user