Laravel+React多租户SaaS系统租户路由最佳实践咨询
Laravel多租户SaaS路由最佳实践(配合React前端)
不用纠结二选一,核心思路是分层规划路由职责,让tenant.php和api.php各司其职,配合实现租户内的页面渲染与数据交互。下面是具体方案和理由:
1. 明确两个路由文件的定位
tenant.php:聚焦租户上下文初始化,是所有租户相关请求的入口。它的核心作用是通过中间件完成租户识别(比如从子域名、路径前缀、请求头提取租户ID)、租户切换、基础权限校验(确认当前用户属于该租户)。这里适合放租户后台的页面路由(比如返回React SPA的入口视图)。api.php:承载无状态的数据交互,专门处理React前端发起的AJAX/fetch请求(比如用户管理表格的列表查询、增删改查)。需要给它绑定租户上下文,确保所有API请求都在指定租户的范围内操作。
2. 具体实现步骤
步骤1:给API路由添加租户识别中间件
把tenant.php里的租户中间件(比如你自定义的EnsureTenantIsIdentified)加到API路由组中,确保所有API请求先完成租户身份校验。
比如在RouteServiceProvider中配置:
// app/Providers/RouteServiceProvider.php public function boot() { $this->routes(function () { // ... 其他路由配置 Route::prefix('api') ->middleware(['api', 'tenant.identify']) // 追加租户识别中间件 ->namespace($this->namespace) ->group(base_path('routes/api.php')); }); }
或者直接在api.php内分组:
// routes/api.php Route::middleware('tenant.identify')->group(function () { // 租户内的用户管理API Route::get('/users', [TenantUserController::class, 'index']); Route::post('/users', [TenantUserController::class, 'store']); Route::put('/users/{user}', [TenantUserController::class, 'update']); // 其他租户相关API });
步骤2:tenant.php聚焦页面路由
在tenant.php里只放租户后台的页面入口路由,返回React SPA的承载视图(或直接返回SPA的HTML文件):
// routes/tenant.php Route::middleware(['tenant.identify', 'auth:tenant'])->group(function () { // 用户管理页面入口 Route::get('/users', function () { return view('tenant.spa'); // 这个视图负责加载React应用 }); // 其他租户后台页面路由 });
步骤3:React前端请求处理
React发起API请求时,确保请求携带租户标识:
- 如果是子域名多租户:请求地址为
https://{tenant}.yourdomain.com/api/users,中间件自动从子域名提取租户ID; - 如果是路径前缀多租户:请求地址为
https://yourdomain.com/{tenant}/api/users,中间件从路径提取租户ID; - 也可以通过请求头
X-Tenant-ID传递租户ID,中间件读取该头信息完成识别。
3. 为什么这是最佳实践
- 职责分离:页面路由和API路由各司其职,代码结构清晰,后期维护成本低;
- API复用性:带租户上下文的API可以直接给React、移动端APP等多端复用,无需重复编写租户逻辑;
- 符合API设计规范:
api.php默认包含throttle、bindings等适合API的中间件,天然支持无状态RESTful设计; - 权限粒度可控:可以在租户中间件之后,给API路由追加租户内的权限中间件(比如
can:manage-users),细粒度控制操作权限。
4. 避坑提醒
- 不要把API逻辑写到
tenant.php中,否则会和web路由混在一起,导致路由结构混乱; - 确保所有租户API都经过租户识别中间件,严格防止跨租户数据访问;
- 如果用JWT/Passport做身份验证,要确保token与租户绑定(比如token payload包含租户ID),验证时同时校验用户所属租户。
内容的提问来源于stack exchange,提问作者Maison012
相关产品推荐
相关产品推荐

