
本文介绍在跨域、异构数据库(postgresql/mysql)、不同 session 驱动(file/database)的 laravel 应用间,避免直接共享 session,转而通过 oauth 2.0 实现安全、可扩展的单点登录方案。
本文介绍在跨域、异构数据库(postgresql/mysql)、不同 session 驱动(file/database)的 laravel 应用间,避免直接共享 session,转而通过 oauth 2.0 实现安全、可扩展的单点登录方案。
在实际企业级部署中,常需让多个 Laravel 应用(如管理后台 A 和客户门户 B)共用一套用户身份体系,但它们运行在不同域名(如 a.example.com 和 b.example.com)、使用不同数据库(PostgreSQL vs MySQL)、甚至配置了不兼容的 Session 存储方式(file vs database)。此时,强行同步或共享加密 Session 数据不仅技术上不可靠(Laravel 的 APP_KEY 加密绑定、Session 签名机制、CSRF token 绑定等均会失效),更严重违背安全最佳实践——Session 是有状态、有生命周期、与具体应用上下文强耦合的私有凭证,不应被“复制”或“透传”。
✅ 正确路径:采用标准协议解耦认证逻辑
推荐使用 Laravel Passport(基于 OAuth 2.0 的第一方 API 认证方案)构建中心化认证服务。以项目 A 作为认证服务器(Auth Server),项目 B 作为受信任的客户端(First-Party Client),实现真正的单点登录(SSO):
-
在项目 A(主认证端)启用 Passport
composer require laravel/passport php artisan migrate php artisan passport:install
在
AuthServiceProvider@boot()中调用Passport::routes(),并配置config/auth.php的apiguard 使用passportdriver。 -
为项目 B 创建第一方客户端
在项目 A 后台运行:php artisan passport:client --password --name="Project B"
记录返回的
id和secret—— 这将用于项目 B 的 OAuth 请求。
Laravel Cloud下载Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
-
在项目 B(客户端)配置 OAuth 消费
安装 Guzzle(用于 HTTP 请求):composer require guzzlehttp/guzzle
在登录逻辑中(例如
LoginController@login),当用户选择“跳转至项目 B”时,不再尝试写入 B 的 Session,而是重定向至 A 的授权端点:// 项目 B 中的登录后跳转逻辑 return redirect()->away('https://a.example.com/oauth/authorize?' . http_build_query([ 'client_id' => config('services.passport.client_id'), 'redirect_uri' => config('services.passport.redirect_uri'), 'response_type' => 'code', 'scope' => '', ])); -
A 授权 → B 获取 Token → 建立本地 Session
用户在 A 完成登录并授权后,A 将重定向回 B 的redirect_uri并附带code。B 用该 code 向 A 的/oauth/token换取访问令牌(Access Token),再用此 Token 调用 A 的/api/user获取用户信息,最后在 B 内部创建独立、合法的本地 Session(例如Auth::login($user)):// B 的回调控制器(如 /auth/callback) $tokenResponse = Http::asForm()->post('https://a.example.com/oauth/token', [ 'grant_type' => 'authorization_code', 'client_id' => config('services.passport.client_id'), 'client_secret' => config('services.passport.client_secret'), 'redirect_uri' => config('services.passport.redirect_uri'), 'code' => $request->code, ]); $accessToken = json_decode($tokenResponse->body())->access_token; $user = Http::withToken($accessToken)->get('https://a.example.com/api/user')->json(); $localUser = User::firstOrCreate(['email' => $user['email']], $user); Auth::login($localUser); // ✅ 此 Session 由 B 自主管理,完全合规 return redirect()->intended('/');
⚠️ 关键注意事项:
-
绝不共享
APP_KEY:即使临时共享,也会导致 CSRF token 泄露、加密 Cookie 可被篡改等高危风险; -
域名隔离是前提:利用
SameSite=None; SecureCookie + HTTPS 保障跨域请求安全,但 Session 本身仍严格限定于各自主域; - 数据同步按需进行:用户基础信息可通过 API 同步,敏感操作(如密码修改)应始终由认证源(A)主导;
-
退出需全局处理:实现“单点登出”需在 A 提供
/oauth/revoke接口,并在 B 登出时主动调用(或借助 Passport 的tokens表清理逻辑)。
总结:Session 不是共享资源,而是认证结果的本地缓存。用 OAuth 2.0 将认证职责收归单一可信源,让每个 Laravel 应用专注维护自己的 Session 生命周期——这才是面向服务架构下安全、可维护、可水平扩展的正确解法。

















