Laravel/Next.js多租户应用无感知用户认证与注册方案问询
多租户环境下的无缝静默认证实现方案(Laravel Sanctum + Next.js)
可行性说明:Sanctum完全适用
不需要更换其他认证包,Sanctum的SPA认证和API令牌机制完全支持这种跨子域的静默认证场景,结合Stancl/Tenancy的多租户能力就能实现需求。
具体实现步骤
后端(Laravel + Stancl/Tenancy + Sanctum)
配置跨子域Cookie共享
- 修改
config/sanctum.php,将stateful配置为包含所有可信租户子域的数组:
生产环境建议明确指定域名,避免使用通配符带来的安全风险。'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'crm.tenant1.com,crm.tenant2.com')), - 修改
config/session.php,将domain设置为根域名(带前置点):
这样租户主站(tenant1.com)的登录Cookie可以被子域(crm.tenant1.com)读取。'domain' => '.tenant1.com',
- 修改
租户主站添加用户信息接口
在租户主站的Laravel项目中新增接口,返回当前登录用户的基础信息,同时限制仅可信子域访问:// routes/api.php Route::middleware(['auth:sanctum'])->get('/user-info', function (Request $request) { $allowedOrigins = ['https://crm.tenant1.com']; if (!in_array($request->header('Origin'), $allowedOrigins)) { abort(403, 'Unauthorized origin'); } return response()->json([ 'external_id' => $request->user()->id, 'name' => $request->user()->name, 'email' => $request->user()->email, ]); });帮助台后端实现静默认证逻辑
在帮助台的Laravel项目中新增静默认证接口,处理用户同步与自动登录:// routes/api.php(需在Tenancy路由组内) Route::post('/silent-auth', function (Request $request) { $tenant = Tenant::current(); $requestOriginHost = parse_url($request->header('Origin'), PHP_URL_HOST); if (!$tenant || $tenant->domain !== $requestOriginHost) { abort(403); } $userData = $request->validate([ 'external_id' => 'required|string', 'name' => 'required|string', 'email' => 'required|email', ]); // 检查帮助台是否已存在该租户的用户 $user = User::where('tenant_id', $tenant->id) ->where('external_user_id', $userData['external_id']) ->first(); if (!$user) { // 自动创建用户,设置随机密码(用户无需手动登录) $user = User::create([ 'tenant_id' => $tenant->id, 'external_user_id' => $userData['external_id'], 'name' => $userData['name'], 'email' => $userData['email'], 'password' => Hash::make(Str::random(32)), ]); } // 会话登录用户(SPA场景推荐) Auth::login($user); return response()->json(['status' => 'success']); });注意:帮助台的用户模型需添加
external_user_id关联租户主站用户ID,tenant_id实现租户数据隔离。
前端(Next.js)
- 页面初始化时的静默认证检查
在根布局组件中,页面加载时自动检查登录状态,未登录则触发静默认证:// app/layout.js useEffect(() => { const initAuth = async () => { // 先检查帮助台本地登录状态 try { const res = await fetch('/api/user', { credentials: 'include' }); if (res.ok) return; } catch (err) {} // 未登录则请求租户主站用户信息 try { const tenantMainDomain = window.location.origin.replace('crm.', ''); const userRes = await fetch(`${tenantMainDomain}/api/user-info`, { credentials: 'include' }); if (!userRes.ok) throw new Error('Tenant site not authenticated'); const userData = await userRes.json(); // 提交到帮助台静默认证接口 await fetch('/api/silent-auth', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify(userData), }); // 认证成功后刷新状态 window.location.reload(); } catch (err) { // 引导用户到租户主站登录 window.location.href = `${tenantMainDomain}/login`; } }; initAuth(); }, []);
最佳实践
- 安全防护:
- 严格校验请求来源,仅允许可信子域访问用户信息接口;
- 对租户主站返回的用户信息添加签名(如HMAC),防止数据篡改;
- 仅同步必要字段,禁止传递敏感数据。
- 租户隔离:
- 帮助台所有用户操作必须绑定租户上下文,数据库层面添加
tenant_id索引; - 利用Stancl/Tenancy的中间件确保租户数据完全隔离。
- 帮助台所有用户操作必须绑定租户上下文,数据库层面添加
- 状态一致性:
- 监听租户主站登录Cookie变化,同步注销帮助台会话;
- 设置统一的会话过期时间,避免两端状态不一致。
- 错误处理:
- 静默认证失败时,明确引导用户到租户主站登录,避免无提示异常;
- 记录认证流程日志,便于问题排查。
- 性能优化:
- 缓存已同步的用户信息,减少重复请求;
- 将静默认证逻辑放在页面加载早期,降低用户感知延迟。
内容的提问来源于stack exchange,提问作者Mostafa Lotfi
相关产品推荐
相关产品推荐

