【问题标题】:Laravel, 2 projects in 2 domains same sessionLaravel,2个领域的2个项目同一个会话
【发布时间】:2017-06-03 12:13:28
【问题描述】:

我正在 2 个不同的域 domain1.tld 和 domain2.tld 中创建 2 个项目。

domain1.tld 是主要的事件生产者页面,domain2.tld 是它的事件之一。我想共享相同的会话(它们实际上共享相同的数据库和相同的 apache 服务器)。我尝试将会话驱动程序更改为“数据库”并创建一个会话表,但没有任何反应,如果我登录 domain1.tld,在 domain2.tld 中没有任何反应。

我确实在网上搜索过,但我什么也没找到

【问题讨论】:

  • 可以使用redis来存储session值
  • @Chris:这个问题是关于两个不同的域,而不是子域
  • 我的错 - 撤回

标签: php laravel session


【解决方案1】:

你不能以你的方式这样做......

当您设置会话时,在浏览器中设置一个 cookie,用于跟踪服务器端存储的会话。

如果你想在两个域之间共享会话,你应该在站点机器人之间共享 cookie,你不能这样做(你可以在一个域的子域中这样做)

但是有一个小技巧: 最简单的解决方法是将登录/凭据信息从网站 A 传递到网站 B,并让网站 B 设置单独的 cookie。例如,在登录网站 A 后,您可以使用加密的查询字符串将他们快速重定向到网站 B。然后网站 B 可以读取信息,设置自己的 cookie,并将用户重定向回网站 A。

这很混乱,但可能。

【讨论】:

    【解决方案2】:

    第 1 步:为共享会话数据设置会话驱动程序

    首先,将会话驱动程序设置为跨两个域共享的数据库或缓存。您的会话驱动程序不能是文件

    第 2 步:实施跨域会话 ID

    会话 id 由 Laravel 中的 cookie 传递。由于您的网站位于不同的域中,因此会话 cookie 不会转移。解决此问题的一种方法是将它们附加到所有请求的查询字符串中,如下所示:domain2.tld/?session_token=abcds2342

    在您的代码中必须有一些登录来检测会话,然后查询数据库/缓存(您的会话驱动程序)以获取结果。如果找到结果,则手动设置会话 ID 并启动会话:

    session_id('abcds2342');
    session_start();
    

    仔细检查 IP 地址和会话 ID 防止人们猜测别人的 SessionID 从而 以其他人身份登录

    第 2A 步:为此,您可以实现一个覆盖 StartSession 的自定义中间件。这个中间件应该覆盖 getSession 并且在它检查 cookie 中的 session_id 之前,检查请求中是否存在令牌。示例代码如下:

    <?php
    
    namespace App\Http\Middleware;
    
    use Illuminate\Session\Middleware\StartSession;
    use Illuminate\Http\Request;
    
    use App\SessionShare;
    
    use Closure;
    
    class StartSessionWithSharer extends StartSession
    {
    
        /**
         * Get the session implementation from the manager.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return \Illuminate\Session\SessionInterface
         */
        public function getSession(Request $request)
        {
            $session = $this->manager->driver();
    
            /**
             * Check if we can find a valid session token from saved records
             */
    
                if($request->get('session_token') && !empty($request->get('session_token'))) {
                    $sessionShare = SessionShare::valid()->whereToken($request->get('session_token'))->first();
    
                    if($sessionShare)
                        $session_id = $sessionShare->session_id;
                }
    
            /**
             * Fallback to session in browser
             */
    
                if(!isset($session_id) || !$session_id)
                    $session_id = $request->cookies->get($session->getName());
    
            $session->setId($session_id);
    
            return $session;
        }
    }
    

    第 2B 步:然后创建一个自定义服务提供者来覆盖 SessionServiceProvider,如下所示:

    <?php namespace App\Providers;
    
    
    class CustomSessionServiceProvider extends \Illuminate\Session\SessionServiceProvider
    {
        /**
         * Register the service provider.
         *
         * @return void
         */
        public function register()
        {
            $this->registerSessionManager();
    
            $this->registerSessionDriver();
    
            $this->app->singleton('App\Http\Middleware\StartSessionWithSharer');
        }
    }
    

    然后从 config/app.php 中删除旧的 SessionServiceProvider 并改用上面的方法。

    第 2C 步:然后为表创建 App\SessionShare 模型以存储会话 ID。此外,上面的代码不负责检查 IP 地址,因此您必须添加它以使其安全并防止暴力攻击

    第 2D 步:哦,最后别忘了为所有请求附加 session_token 的 get 参数

    请注意,上述实现是针对数据库会话驱动程序的。当然,您也可以对缓存驱动程序执行此操作。唯一会改变的是模型实现(步骤 2C)来验证会话

    【讨论】:

    • 哇儿子好,谢谢,我有最后一个问题,这是一个好习惯吗?或者最好不要这样做
    • 如果可以避免,请考虑避免。这种做法存在一些问题(例如,安全性 - 如果未检查 IP 地址,UX - 如果检查了 IP 地址,想象一下如果用户在会话中间更改他的 IP 会发生什么 - 它会将他注销)。如果您可以使用subdomains,则不会出现此问题。恰当的例子 - Google Drive、Mail、Calendar 等都在 google.com 域中,具有单独的子域
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-20
    • 2019-03-30
    相关资源
    最近更新 更多