Laravel 12 中使用 stancl/tenancy v4 实现域名级多租户数据隔离,核心是每个租户绑定独立数据库并通过域名路由识别租户,采用运行时动态配置连接与请求生命周期内绑定租户上下文的方式,不再依赖全局中间件自动切换。

在 Laravel 12 中使用 stancl/tenancy v4 实现域名级多租户数据隔离,核心是通过「每个租户绑定独立数据库 + 域名路由识别租户」完成物理隔离。v4 不再依赖全局中间件自动切换连接,而是改用「运行时动态配置数据库连接」+「请求生命周期内绑定租户上下文」的方式,更灵活也更可控。
安装与基础配置
先确保 Laravel 12 已升级到 PHP 8.2+,并启用 `ext-pdo_pgsql` 或 `ext-pdo_mysql`(根据你用的数据库)。执行:
composer require stancl/tenancy:^4.0-
php artisan tenancy:install—— 会发布配置、迁移和 ServiceProvider - 运行
php artisan migrate(主站数据库,含tenants表)
编辑 config/tenancy.php,重点设置:
-
'tenant_model' => App\Models\Tenant::class(需创建该模型) -
'database' => ['driver' => 'mysql'](租户库默认驱动,可按需覆盖) -
'identification' => ['strategies' => [Stancl\Tenancy\Identification\Strategies\DomainStrategy::class]]—— 启用域名识别
定义租户模型与域名字段
生成租户模型:php artisan make:model Tenant -m,在迁移中添加域名字段:
$table->string('domain')->unique(); // 如 tenant1.example.com
模型 App\Models\Tenant 需实现 Stancl\Tenancy\Contracts\TenantWithDatabase 接口,并定义 getDatabaseName() 方法(如返回 'tenant_' . $this->id)。
v4 默认不自动建库,建议在 TenantCreated 事件中手动创建数据库(用 DB::statement),或配合 tenancy/dbal 扩展。
域名路由与租户识别流程
v4 使用 DomainStrategy,它会在请求进入时解析 Host 头,匹配 tenants.domain 字段。例如访问 shop1.yoursaas.com,系统会查找 domain = 'shop1.yoursaas.com' 的租户。
关键点:
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- 确保 Web 服务器(Nginx/Apache)把所有子域流量都指向 Laravel 入口(不要 404 子域)
- Laravel 的
APP_URL应设为通配主域,如https://*.yoursaas.com(开发环境可用localhost+ hosts 模拟) - 租户域名必须完整匹配(含端口),开发时建议用
tenant1.test:8000并配本地 hosts
数据隔离与连接切换
v4 不再全局替换 DB 连接,而是在每次请求中由 TenantManager 动态设置连接参数。你无需手动调用 DB::purge() 或 Config::set()。
只需确保:
- 模型继承
Stancl\Tenancy\Models\Tenant(用于租户管理)或使用UsesTenantConnectiontrait(用于普通模型,如 User) - 在
app/Providers/EventServiceProvider.php中监听TenantIdentified事件,可在此做租户专属初始化(如设置语言、缓存前缀) - 所有 Eloquent 查询默认走租户库 —— 只要当前请求已识别租户且模型没显式指定 connection
若需跨租户操作(如后台统计),用 Tenant::find(1)->run(...) 包裹闭包,内部自动切换连接。
常见问题处理
启动时报 Database does not exist:检查租户数据库是否真实存在,v4 不自动创建;可在 TenantCreated 事件里加 DB::statement("CREATE DATABASE IF NOT EXISTS {$tenant->getDatabaseName()}")。
本地开发子域不生效:确认 php artisan serve 支持 Host 头(Laravel 12 默认支持),或改用 Valet / DDEV / Nginx 转发。
Artisan 命令无法识别租户:命令行无 Host 头,需用 --tenant=xxx 参数,或在命令中手动调用 Tenant::first()->makeCurrent()。










