Laravel:在多个域上共享会话数据

Posted

技术标签:

【中文标题】Laravel:在多个域上共享会话数据【英文标题】:Laravel: share session data over multiple domains 【发布时间】:2015-01-05 10:46:53 【问题描述】:

我正在 Laravel 中构建一个多域/多商店电子商务应用程序,并希望在用户从商店更改为商店时保持登录状态。

但据我所知,Laravel 的 Auth 服务将登录用户保存在会话中,其他域无法访问会话。

有没有办法(可能是一个包)来实现这一点,而不会让我的应用程序容易出现可能的安全问题?

提前致谢!

【问题讨论】:

【参考方案1】:

我也在开发类似的单点登录系统,仍在努力寻找解决方案,但这是一个开始http://laravel.io/forum/03-14-2014-multiple-domains-how-to-share-login

在 laravel 上,您可以将 /app/config/session.php 驱动程序更改为 cookie


编辑:

这就是我所做的。

您可以使用像素图像跨域共享 cookie。 例如,当您登录 domain1.com 时,您想在 domain2.com 上创建一个 cookie,在登录 domain1.com 后,您需要拥有类似的东西

<img src="http://www.domain2.com/create-cookie?param=hash">

在 domain2.com 上面的路由:

    将首先检查用户是否登录
      如果未登录将读取哈希(例如电子邮件地址),检查是否有使用该电子邮件的用户,并在那里登录,同时设置一个 cookie

【讨论】:

警告:不要以纯文本形式发送电子邮件,这意味着我可以编辑 html 标签并基本上登录到其他域上的任何帐户。使用您的应用密钥加密文本。【参考方案2】:

您可以手动设置会话 cookie 将注册的域,从而让它们在不同的站点上持续存在。只需在以下部分编辑config/session.php

<?php
/*
    |--------------------------------------------------------------------------
    | Session Cookie Domain
    |--------------------------------------------------------------------------
    |
    | Here you may change the domain of the cookie used to identify a session
    | in your application. This will determine which domains the cookie is
    | available to in your application. A sensible default has been set.
    |
    */

    'domain' => null,
?>

不过,您仍然仅限于一个***域。所以你可以有store1.shops.comstore2.shops.com 共享会话,但不能有myshop.comshopsmart.com

如果您需要这种格式的东西,您可能会通过创建身份验证服务并使用访问令牌来验证凭据来获得更好的效果。你也可以看看OneLogin之类的服务。

【讨论】:

已测试但无法正常工作。 @Chirag 答案虽然有效【参考方案3】:
    在域 A 中捕获会话 id Session::getId() 通过 HTTP POST 将捕获的会话 ID 发送到域 B 访问域B中发送的会话ID $sessionid_from_domainA = $_POST['session_from_A'] 在域 B 中设置会话 Session::setId($sessionid_from_domainA) 在域 B Session::start() 中启动会话

【讨论】:

我希望这是可能的,但事实并非如此。如果它是相同的 laravel 安装但具有不同的域,一旦您从域 A 登录到您的应用程序,您就无法向自身发送 POST 请求并启动会话。 我找到了一种更简单的方法,请检查我的答案【参考方案4】:

    在域 A 上创建一个像这样的图像&lt;img src="https://DOMAINB.com/setcookie?id= Session::getId() " style="display:none;" /&gt;

    在域 B 上创建一个路由,如下所示:

.

Route::get('setcookie', function()
  Session::setId($_GET['id']);
  Session::start();
  return 'Cookie created';
);`
    完成,现在您应该可以通过$user = Auth::User; 获取您的用户了

【讨论】:

对于任何使用此方法的人,我不确定此方法是否安全,这是 google 过去的做法,但现在他们使用 OAuth 对于可以存储在会话中的简单事物,这是救命稻草 我使用了这种方法,我做的唯一小改动是传递加密的会话 id,而不是普通的 id。像这样:Session::setId(Crypt::decrypt($_GET['id'])); 另外,我在 IE9 及以下版本中遇到了问题。他们需要设置 P3P 标头,以便为其他域正确设置 cookie。所以我在 Session::start() 下方添加了这一行:header('P3P: CP="This is not a policy"'); 您可以在this post 中阅读有关 P3P 标头的更多信息。 @HarryPotts 是否需要将会话存储在数据库中才能正常工作?【参考方案5】:

如果你想在多个子域之间共享会话,那么你必须设置域名 config/session.php 已经设置了域名。

示例:如果你有 new.example.com 和 test.example.com 那么你必须将域名设置为 example.com

'domain'     => env('SESSION_DOMAIN_URL','.example.com')

那里的解决方案对我有用,特别是设置域,然后清除我的浏览器 cookie 和缓存。

【讨论】:

最好还是创建一个 .env 变量,例如 (SESSION_DOMAIN=.example.com)。在同一个 laravel 项目中为我工作。 cookie只能发给特定的子域吗?比如 new.example.com 和 test.example.com 只有?而不是其他子域?要从另一个 Laravel 项目访问会话,我是否必须再次实现 User 模型?我应该将驱动程序更改为 Cookie 而不是文件吗? 我对这种方法有一点问题。我使用多个动态 dns 域。即 domain1.freemyip.com、domain2.freemyip.com 等【参考方案6】:

我知道这并不完全符合我们的要求,但出于开发和测试目的,我这样做了:

在 config/session.php 中,尝试更改这一行

'path' => '/',

进入这个

'path' => '/;SameSite=None; secure',

允许我从不同的域进行身份验证。

现在,您应该能够编写一个简单的中间件来阻止不需要的主机。像这样。

namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Closure;

class TrustedHosts
    public function handle($request, Closure $next)
        //$host = $request->getHost();
        $host = $request->headers->get('origin');
        $enviroment = env('APP_ENV');

        if ( $enviroment == 'development' ) 
            $trustedHosts = array('localhost', 'dev.mydomain.com');
        
        else 
            $trustedHosts = array('anotherdomain.com', 'mydomain.com');
        
        
        $isHostTrusted = in_array($host, $trustedHosts);
        
        if ( !$isHostTrusted ) return response("I'm a teapot", 418); //Or any other code and message that you prefer.
        return $next($request);
    

并将其分组到包含会话内容的中间件组中。

【讨论】:

【参考方案7】:

基于Chirag Prajapati 的这个答案。你可以在 env 条目中使用$_SERVER['HTTP_HOST']

来自/config/session.php

'domain' => env('SESSION_DOMAIN', $_SERVER['HTTP_HOST']),

然后从应用程序根目录:php artisan config:clear 并且不要关注警告消息,只需确保最后您已收到Configuration cache cleared! 这样您的应用程序会话将在您拥有的任何域上正常工作。

【讨论】:

以上是关于Laravel:在多个域上共享会话数据的主要内容,如果未能解决你的问题,请参考以下文章

通过多个 Laravel 5 安装跨子域共享身份验证会话

如何从Angular向同一域上的Laravel API发送请求?

如何在同一个域上运行多个 Laravel 实例?

单个域上多个 laravel 应用程序的虚拟主机别名

在 2 个 laravel 应用程序之间共享会话

Laravel与Socket.io Nodejs共享会话