Skip to content

基础能力

CatchAdmin 多租户扩展通过租户上下文切换数据库,并同步隔离缓存、日志、文件系统和队列。中央数据库负责租户管理与监控数据,每个租户使用独立数据库保存业务数据。

租户识别

系统提供两种全局识别模式:

模式租户定位方式关键约束
domain请求 Host 匹配租户 Domain每个租户需要可访问的域名、DNS、TLS 和反向代理配置
shared_domain登录参数选择租户,API 请求头传递租户 UUID使用统一后台域名,租户 API 需要携带 X-Tenant

shared_domain 模式的典型请求流程:

  1. 用户通过 /#/login?tenant=<uuid> 进入租户登录页。
  2. 前端在当前标签页的 sessionStorage 保存租户 UUID,并从 localStorage 读取按租户隔离的 Token。
  3. 后续租户 API 携带 X-Tenant: <uuid>Authorization: Bearer <tenant-token>
  4. 中间件初始化租户数据库、缓存、日志、文件系统和队列上下文。

未携带 X-Tenant 的请求进入中央上下文。完整模式配置和 Token 隔离规则见配置说明

租户生命周期

后台支持完整的租户生命周期管理:

  • 创建:分配启用套餐,创建租户记录、独立数据库和初始管理员,并同步套餐权限。
  • 编辑:更新租户资料、订阅和数据库连接配置。
  • 续期:更新租户到期时间。
  • 变更套餐:切换到启用套餐,并同步新套餐的菜单权限。
  • 停用:暂停租户访问,记录停用原因和备注。
  • 恢复:恢复租户状态,保留本次恢复原因和备注。
  • 删除:删除租户数据库及中央租户记录。
  • 操作记录:记录创建、编辑、续期、变更套餐、停用和恢复等关键动作。

创建租户和变更套餐接口都校验套餐启用状态,禁用套餐不会出现在可选套餐列表中。

订阅与可用状态

  • 一年期:未填写结束日期时,以租户创建日期加一年作为有效期。
  • 自定义期限:使用管理员设置的结束日期。
  • 永久:没有结束日期限制。

租户到期状态分为正常、即将到期、已到期和永久。结束日期在未来 7 天内时显示“即将到期”。启用且未到期的租户属于可用租户;停用或已到期租户的业务 API 访问会被拒绝,也不会被租户命令遍历。

中央管理权限

租户管理为中央管理员提供独立的角色权限:

  • 租户列表、读取、新增、更新和删除。
  • 租户续期、变更套餐、停用和恢复。
  • 调度任务列表、同步、立即执行和日志清理。

运行 TenancyMenusSeeder 后,可按角色分配这些权限。普通管理员只获得角色明确授权的操作能力。

操作记录

租户操作记录包含操作类型、操作人、时间、原因、备注及变更前后的核心数据,用于审计租户生命周期变化。

日志隔离

中央日志保存在 storage/logs。租户初始化后,配置在 tenancy.logging.channels 且具有文件路径的日志通道会切换到以下目录:

text
storage/logs/tenant-{uuid}/...

默认隔离 dailysinglequery 通道。后台日志查看器可以按租户选择日志文件。排查异常时应同时确认异常发生时间和最新日志,历史记录仅代表当时的运行状态。

文件系统隔离

租户包默认隔离三个本地磁盘:

磁盘用途可见性租户目录
uploads头像、商品图、附件等业务上传公开storage/uploads/tenant-{uuid}/...
static需要应用内部读取的静态文件私有storage/static/tenant-{uuid}/...
certs证书、密钥等敏感文件私有storage/certs/tenant-{uuid}/...

uploads 通过 public/uploads -> storage/uploads 软链接公开访问,适合公开业务文件。证书、密钥和需要鉴权的文件应保存到 staticcerts 或其他私有磁盘。

租户上传接口返回包含租户目录的相对路径,例如:

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}/... 路径,通过公开软链接访问。

staticcerts 保持私有目录,不提供直接浏览器 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 任务,查看执行状态和历史日志。