Laravel多域名场景下的用户跨域登录认证问题咨询
解决Laravel多域名应用跨域登录问题
这个问题我之前在处理多域名SaaS应用时碰到过,核心原因是浏览器的同源策略限制了Session Cookie只能在当前域名下生效,导致你在example-A.com登录的用户无法在example-B.com自动获取会话状态。下面是一套完整的解决方案:
1. 配置跨域Session Cookie
首先要让Laravel生成的Session Cookie能在所有目标域名下生效,这需要修改Session配置:
在
.env文件中设置顶级域名作为Session域名(注意前面的点):SESSION_DOMAIN=.example.com假设你的三个域名都是
example-A.com、example-B.com、example-C.com,它们的顶级域名是example.com,加上前缀点后,Cookie会被所有子域名共享。打开
config/session.php,确认以下配置项:'domain' => env('SESSION_DOMAIN', null), 'same_site' => env('SESSION_SAME_SITE', 'none'), 'secure' => env('SESSION_SECURE', true),same_site=none:允许跨域场景下浏览器传递Cookie(必须配合secure=true)secure=true:要求Cookie仅通过HTTPS传输(生产环境必须开启,本地开发可临时设为false)
2. 自定义跨域登录逻辑
仅配置Cookie还不够,因为你是在example-A.com的后台主动登录其他域名的用户,需要主动同步会话状态到目标域名。可以通过签名URL验证的方式实现:
步骤1:生成跨域登录签名URL
在你的后台登录处理方法中,生成一个带签名的跳转URL,用于目标域名验证用户身份:
public function loginCrossDomainUser(User $user, string $targetDomain) { // 生成过期时间(5分钟内有效) $expiresAt = now()->addMinutes(5)->getTimestamp(); // 生成签名(用APP_KEY确保不可伪造) $signature = hash_hmac('sha256', "{$user->id}|{$expiresAt}", config('app.key')); // 拼接目标域名的登录验证URL $loginUrl = "https://{$targetDomain}/auth/cross-domain-login?user_id={$user->id}&expires={$expiresAt}&signature={$signature}"; // 跳转到目标域名完成登录 return redirect()->away($loginUrl); }
步骤2:在目标域名添加验证路由
在所有需要支持跨域登录的域名的routes/web.php中添加路由:
use App\Http\Controllers\Auth\CrossDomainLoginController; Route::get('/auth/cross-domain-login', [CrossDomainLoginController::class, 'handle'])->name('cross-domain.login');
步骤3:实现验证登录逻辑
创建CrossDomainLoginController,处理签名验证并完成登录:
namespace App\Http\Controllers\Auth; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Routing\Controller; class CrossDomainLoginController extends Controller { public function handle(Request $request) { // 验证参数是否齐全 $request->validate([ 'user_id' => 'required|integer', 'expires' => 'required|integer', 'signature' => 'required|string', ]); $userId = $request->user_id; $expires = $request->expires; $signature = $request->signature; // 验证链接是否过期 if (now()->getTimestamp() > $expires) { abort(403, '登录链接已过期,请重新操作'); } // 验证签名是否合法 $expectedSignature = hash_hmac('sha256', "{$userId}|{$expires}", config('app.key')); if (!hash_equals($expectedSignature, $signature)) { abort(403, '无效的登录请求,请重试'); } // 查找用户并完成登录 $user = User::findOrFail($userId); Auth::login($user); // 跳转到目标域名的首页或指定页面 return redirect('/'); } }
3. 关键注意事项
- 统一APP_KEY:所有域名的Laravel应用必须使用相同的
APP_KEY,否则签名验证会失败(因为签名依赖APP_KEY)。 - HTTPS强制开启:生产环境必须使用HTTPS,否则
SameSite=None的Cookie会被浏览器拒绝。 - iframe优化体验:如果不想让用户看到跳转过程,可以用iframe加载目标域名的登录验证URL,但需要在目标域名的响应头中设置
X-Frame-Options: ALLOW-FROM https://example-A.com(或者更宽松的配置),允许后台域名嵌入。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

