Laravel: 在多个域名之间共享会话数据

15

我正在使用Laravel构建一个多域名/多商店的电子商务应用程序,希望用户在从一个商店切换到另一个商店时仍然保持登录状态。

但据我所知,Laravel的身份验证服务将已登录的用户保存在会话中,其他域名无法访问这些会话。

是否有一种方法(也许是一个软件包)可以实现这一点,而不会让我的应用程序容易受到安全问题的影响?

提前感谢!

7个回答

9
  1. 在域A中捕获会话ID Session::getId()
  2. 通过HTTP POST将捕获的会话ID发送到域B
  3. 在域B中访问已发送的会话ID $sessionid_from_domainA = $_POST['session_from_A']
  4. 在域B中设置会话 Session::setId($sessionid_from_domainA)
  5. 在域B中启动会话 Session::start()

我希望这是可能的,但事实并非如此。如果是相同的Laravel安装,但使用不同的域名,一旦您从域A登录到应用程序,您无法向自身发送POST请求并启动会话。 - Omer Farooq
我发现了一个更简单的方法,看看我的答案。 - mateos

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项目中对我有效。 - DAVID AJAYI
可以仅针对特定的子域名发放cookie吗?例如仅限于new.example.com和test.example.com,而不包括其他子域名?如果要从另一个Laravel项目访问会话,我是否需要再次实现用户模型?我应该将驱动程序更改为Cookie而不是文件吗? - Luke Galea
我对这种方法有一点问题。我使用多个动态DNS域名,例如domain1.freemyip.com、domain2.freemyip.com等。 - SaidbakR

4
  1. 在域名A上创建如下的图片:<img src="https://DOMAINB.com/setcookie?id={{ Session::getId() }}" style="display:none;" />

  2. 在域名B上创建一个路由,形式如下:

.

Route::get('setcookie', function(){
  Session::setId($_GET['id']);
  Session::start();
  return 'Cookie created';
});`

完成了,现在你应该能够通过 $user = Auth::User; 获取你的用户。

对于使用此方法的任何人,我不确定它是否安全,这是谷歌以前使用的方法,但现在他们使用OAuth。 - mateos
1
对于那些可以存储在会话中的简单事物,这是救命稻草。 - bksi
我使用了这个方法,唯一的小改变是传递加密的会话ID而不是明文ID。像这样: Session::setId(Crypt::decrypt($_GET['id']));此外,我在IE9及以下版本中遇到了问题。为了使cookie在其他域中正确设置,需要设置P3P头。因此,在Session::start()下面添加了以下行: header('P3P: CP="This is not a policy"');您可以在此帖子中了解有关P3P头的更多信息。 - Harry Potts
@HarryPotts 这个需要将会话存储在数据库中才能工作吗? - mujaffars

2

我知道这不完全是被要求的,但是为了开发和测试目的,我做了以下操作:

在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);
    }
}

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


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 上,上述路由:
  1. 首先检查用户是否已登录。
    1. 如果未登录,则读取哈希(例如电子邮件地址),检查是否有关联该电子邮件的用户,并登录该用户,同时设置一个 Cookie。

2
警告:不要以纯文本形式发送电子邮件,这意味着我可以编辑HTML标记并基本上登录到另一个域上的任何帐户。请使用您的应用程序密钥加密文本。 - mateos

1
您可以手动设置会话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的回答起作用了。 - DAVID AJAYI

0
基于 Chirag Prajapati 的答案。您可以在 env 条目中使用 $_SERVER ['HTTP_HOST']
来自/config/session.php
'domain' => env('SESSION_DOMAIN', $_SERVER['HTTP_HOST']),

然后从应用程序根目录执行:php artisan config:clear,不要关注警告消息,只需确保最终获得了Configuration cache cleared!。通过这种方式,您的应用程序会话将在任何域上正常工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接