主题
基础能力
CatchAdmin 多租户扩展通过租户上下文切换数据库,并同步隔离缓存、日志、文件系统和队列。中央数据库负责租户管理与监控数据,每个租户使用独立数据库保存业务数据。
租户识别
系统提供两种全局识别模式:
| 模式 | 租户定位方式 | 关键约束 |
|---|---|---|
domain | 请求 Host 匹配租户 Domain | 每个租户需要可访问的域名、DNS、TLS 和反向代理配置 |
shared_domain | 登录参数选择租户,API 请求头传递租户 UUID | 使用统一后台域名,租户 API 需要携带 X-Tenant |
shared_domain 模式的典型请求流程:
- 用户通过
/#/login?tenant=<uuid>进入租户登录页。 - 前端在当前标签页的
sessionStorage保存租户 UUID,并从localStorage读取按租户隔离的 Token。 - 后续租户 API 携带
X-Tenant: <uuid>与Authorization: Bearer <tenant-token>。 - 中间件初始化租户数据库、缓存、日志、文件系统和队列上下文。
未携带 X-Tenant 的请求进入中央上下文。完整模式配置和 Token 隔离规则见配置说明。
租户生命周期
后台支持完整的租户生命周期管理:
- 创建:分配启用套餐,创建租户记录、独立数据库和初始管理员,并同步套餐权限。
- 编辑:更新租户资料、订阅和数据库连接配置。
- 续期:更新租户到期时间。
- 变更套餐:切换到启用套餐,并同步新套餐的菜单权限。
- 停用:暂停租户访问,记录停用原因和备注。
- 恢复:恢复租户状态,保留本次恢复原因和备注。
- 删除:删除租户数据库及中央租户记录。
- 操作记录:记录创建、编辑、续期、变更套餐、停用和恢复等关键动作。
创建租户和变更套餐接口都校验套餐启用状态,禁用套餐不会出现在可选套餐列表中。
订阅与可用状态
- 一年期:未填写结束日期时,以租户创建日期加一年作为有效期。
- 自定义期限:使用管理员设置的结束日期。
- 永久:没有结束日期限制。
租户到期状态分为正常、即将到期、已到期和永久。结束日期在未来 7 天内时显示“即将到期”。启用且未到期的租户属于可用租户;停用或已到期租户的业务 API 访问会被拒绝,也不会被租户命令遍历。
中央管理权限
租户管理为中央管理员提供独立的角色权限:
- 租户列表、读取、新增、更新和删除。
- 租户续期、变更套餐、停用和恢复。
- 调度任务列表、同步、立即执行和日志清理。
运行 TenancyMenusSeeder 后,可按角色分配这些权限。普通管理员只获得角色明确授权的操作能力。
操作记录
租户操作记录包含操作类型、操作人、时间、原因、备注及变更前后的核心数据,用于审计租户生命周期变化。
日志隔离
中央日志保存在 storage/logs。租户初始化后,配置在 tenancy.logging.channels 且具有文件路径的日志通道会切换到以下目录:
text
storage/logs/tenant-{uuid}/...默认隔离 daily、single 和 query 通道。后台日志查看器可以按租户选择日志文件。排查异常时应同时确认异常发生时间和最新日志,历史记录仅代表当时的运行状态。
文件系统隔离
租户包默认隔离三个本地磁盘:
| 磁盘 | 用途 | 可见性 | 租户目录 |
|---|---|---|---|
uploads | 头像、商品图、附件等业务上传 | 公开 | storage/uploads/tenant-{uuid}/... |
static | 需要应用内部读取的静态文件 | 私有 | storage/static/tenant-{uuid}/... |
certs | 证书、密钥等敏感文件 | 私有 | storage/certs/tenant-{uuid}/... |
uploads 通过 public/uploads -> storage/uploads 软链接公开访问,适合公开业务文件。证书、密钥和需要鉴权的文件应保存到 static、certs 或其他私有磁盘。
租户上传接口返回包含租户目录的相对路径,例如:
text
uploads/tenant-a23f3fab-ac7d-4c1d-8543-56a93b22aee1/2026-07-18/attachments/example.jpg页面访问时在路径前添加 /:
text
/uploads/tenant-a23f3fab-ac7d-4c1d-8543-56a93b22aee1/2026-07-18/attachments/example.jpg两种模式下的资产访问
domain:租户上下文可由 Host 初始化。启用asset_helper_tenancy后,asset()会生成租户资产地址;需要显式生成租户资产时可使用tenant_asset()。相关路由名称为stancl.tenancy.asset。shared_domain:浏览器直接加载图片时通常不会附加业务 API 使用的X-Tenant请求头。公开上传应直接使用上传接口返回的/uploads/tenant-{uuid}/...路径,通过公开软链接访问。
static 和 certs 保持私有目录,不提供直接浏览器 URL。软链接、路由和详细排障步骤见安装说明与部署说明。
缓存与队列隔离
租户缓存键使用 tenant:<uuid>: 前缀,避免不同租户共享相同缓存键。租户队列上下文会随任务载荷传递,执行时恢复对应租户环境。
队列连接、监控 Trait、Worker 和进度记录见队列系统。
租户命令
需要逐租户执行的 Artisan 命令可继承:
php
use Modules\Tenancy\Commands\TenancyCommand;
class CleanupCommand extends TenancyCommand
{
protected $signature = 'tenant:cleanup';
public function handle(): void
{
$this->info('正在租户 ['.$this->tenant->id.'] 中执行清理');
}
}TenancyCommand 使用 TenantAwareCommand 执行命令,并只遍历启用且未到期的可用租户。命令生成、Scheduler 注册和调度监控见租户命令与调度。
后台运维入口
- 日志查看:按租户查看隔离后的日志文件。
- 队列监控:查看中央任务和租户任务的状态、进度、重试与异常。
- 调度监控:同步 Laravel Scheduler 任务,查看执行状态和历史日志。