Laravel多租户场景下如何为单租户配置多个二级域名?
这个需求完全可以实现,你当前的配置存在两个核心问题,导致域名匹配失败、租户无法解析:
- 域名路由规则层级错误:你当前配置的
admin.localhost、employee.localhost仅能匹配二级域名段为admin/employee的请求,无法匹配你需要的{租户标识}.{角色}.localhost三级域名结构,请求匹配不到对应路由自然会fallback到无域名约束的公共路由。 - 多租户默认解析逻辑不兼容三级域名:Spatie多租户默认的域名租户识别逻辑,是取域名最左段子域作为租户标识匹配,但默认逻辑没有处理多段子域的场景,直接拿全量子域匹配自然找不到对应租户。
具体修复步骤
1. 调整路由域名匹配规则
修改RouteServiceProvider中的路由定义,按照三级域名结构配置匹配规则,注意公共无租户路由要放在最顶部,避免被带参数的域名路由优先匹配:
// 公共无租户路由(安全、登录等页面)放最前面 Route::middleware('web') ->group(base_path('routes/security.php')); // 租户默认前台路由,匹配 {tenantSlug}.localhost 结构 Route::domain('{tenantSlug}.' . config('app.base_domain')) ->middleware('web') ->group(base_path('routes/tenant.php')); // 租户后台路由,匹配 {tenantSlug}.admin.localhost 结构 Route::domain('{tenantSlug}.admin.' . config('app.base_domain')) ->middleware('web') ->name('admin.') ->group(base_path('routes/admin.php')); // 租户员工端路由,匹配 {tenantSlug}.employee.localhost 结构 Route::domain('{tenantSlug}.employee.' . config('app.base_domain')) ->middleware('web') ->name('employee.') ->group(base_path('routes/employee.php'));
提示:路由中定义的
{tenantSlug}参数不需要在控制器方法中注入,后续租户解析逻辑会直接从请求主机名读取,不会影响原有路由的方法签名。
2. 自定义租户查找逻辑,适配三级域名结构
默认的租户查找类仅支持单段子域的租户识别,需要新建自定义租户查找类适配多子域场景:
新建文件app/TenantFinder/SubdomainTenantFinder.php,写入以下代码:
<?php namespace App\TenantFinder; use Illuminate\Http\Request; use Spatie\Multitenancy\Models\Tenant; use Spatie\Multitenancy\TenantFinder\TenantFinder; class SubdomainTenantFinder extends TenantFinder { public function findForRequest(Request $request): ?Tenant { // 拆分主机名段 $hostSegments = explode('.', $request->getHost()); // 无论域名后缀是1段(localhost)还是多段(example.com),第一个段永远是租户slug $tenantSlug = $hostSegments[0] ?? null; if (!$tenantSlug) { return null; } // 按照你自己租户表存租户标识的字段调整,默认如果用id匹配就改对应查询逻辑 return Tenant::where('slug', $tenantSlug)->first(); } }
修改多租户配置文件config/multitenancy.php,将默认的租户查找类替换为自定义类:
'tenant_finder' => \App\TenantFinder\SubdomainTenantFinder::class,
3. 本地环境域名解析配置
本地开发需要确保所有三级域名能指向你的Laravel项目,两种方案选一个即可:
- 方案1:在本地hosts文件中手动添加所有需要用到的域名映射到127.0.0.1
- 方案2:配置dnsmasq做泛域名解析,将
*.localhost统一指向127.0.0.1,后续新增租户不需要重复修改hosts
4. 清除缓存验证
执行路由清除命令php artisan route:clear,再访问对应域名验证:
- 访问
company-a.localhost正常加载租户前台页面 - 访问
company-a.admin.localhost加载admin.php路由定义的后台内容,可通过currentTenant()正常获取company-a租户信息 - 访问
company-a.employee.localhost加载employee.php路由定义的员工端内容
常见排查点:如果还是匹配异常,先执行
php artisan route:list查看所有路由的domain字段是否和预期一致,确认路由规则生效;再检查hosts配置是否正确,确保请求能到达Laravel项目。
内容的提问来源于stack exchange,提问作者Abdullah
相关产品推荐
相关产品推荐

