Laravel在域和子域中共享cookie检测问题

时间:2017-08-18 15:16:47

标签: laravel cookies

我正在研究Laravel 5.4.30。

想象一下,我们有一个域example.com和一个dev.example.com的子域。主域用于主分支,dev子域用于develop分支。我们有cookie通知系统,点击Hide Cookie Notice按钮后会隐藏。这通过永久设置cookie来实现。 我们为每个环境为每个域设置了SESSION_DOMAIN个配置。

对于主域名:

SESSION_DOMAIN=example.com

对于dev子域名:

SESSION_DOMAIN=dev.example.com

现在问题来自这里。如果我们转到example.com并点击隐藏cookie通知,将为主域永久设置cookie。之后我们转到dev.example.com并执行相同的操作。因此,也会为子域设置cookie。但是这个cookie已经在前一个之后设置了。 (顺序很重要) 现在,如果我们刷新子域,我们将再次看到这个通知! (未隐藏)由于浏览器中cookie的.example.com参数中设置了domain,浏览器已读取主Cookie,因此每个子域都会受到影响。但该视图仍然显示通知,因为它无法读取任何cookie以进行隐藏。

无论如何,我不想在所有子域中共享该cookie。我怎样才能做到这一点?我想我应该为cookie名称添加一个前缀。但是我不知道怎么做,laravel会自动为cookie名称添加前缀。

任何解决方案?

3 个答案:

答案 0 :(得分:7)

您需要实现自己的“检索”和“设置”Cookie。

检索(拥有,获取)cookie

使用名称Cookie创建自己的新课程(您喜欢的任何地方,但我会做 app / Foundation / Facades / )。

use \Illuminate\Support\Facades\Cookie as CookieStock;

class Cookie extends CookieStock { 
    //implement your own has(...);
    public static function has($key)
    {
        return ! is_null(static::$app['request']->cookie(PREFIX . $key, null)); //get the prefix from .env file for your case APP_ENV
    }

    //implement your own get(...);
    public static function get($key = null, $default = null) {...}
}

现在打开config / app.php并更改相应的别名(cookie)。

设置(制作)cookies

创建自己的新提供程序(使用工匠),并从 Illuminate \ Cookie \ CookieServiceProvider.php 复制粘贴代码并更改名称空间。 再次打开config / app.php并使用新的服务提供商更改相应的服务提供商。

使用名称CookieJar创建自己的新课程(在任何您喜欢的地方,但我会做 app / Foundation / Cookie / )。

use \Illuminate\Cookie\CookieJar as CookieJarStock;

class CookieJar extends CookieJarStock {

//Override any method you think is relevant (my guess is make(), I am not sure at the moment about queue related methods)

    public function make($name, $value, $minutes = 0, $path = null, $domain = null, $secure = false, $httpOnly = true)
    {
        // check before applying the PREFIX
        if (!empty($name)) {
            $name = PREFIX . $name; // get the PREFIX same way as before
        }

        return parent::make($name, $value, $minutes, $path, $domain, $secure, $httpOnly);
    }
}

更新您自己的Cookie服务提供商中的代码,以使用CookieJar的实现(第19行)。

运行$ composer dump-autoload,你应该完成。

更新

自BorisD.Teoharov提出以来,如果框架在主要版本之间更改CookieJarStock s make()(或任何其他cookie相关函数)的签名,我就做了一个例子repository ,包括可以按原样使用的测试,如果签名发生变化,它将失败。

就这么简单:

public function test_custom_cookie_jar_can_be_resolved()
{
    resolve(\App\Foundation\Cookie\CookieJar::class);
    $this->assertTrue(true);
}

详细说明如何在the corresponding commit diff中查看。

答案 1 :(得分:2)

我已经设置了测试环境,以确保没有遗漏任何细节。

就像我以前的回答一样,我认为使cookie无效对于这种情况就足够了,但是正如@BorisD所建议的那样,这已经足够了,我已经在测试中证实了这一点。

因此,有一些重要的笔记,来自我的经验...

  1. 请勿在子域中混用Laravel版本-如果使用 SESSION_DOMAIN ,则需要确保您的 Laravel版本与之匹配(在根域和子域之间) ),因为我已经在example.com域下尝试了 5.4 ,在dev.example.com下尝试了 5.6 。这显示了我在处理Cookie方面的一些不一致之处,因此,在这些版本之间进行了一些重要的更改,并且可以确定如果混合使用版本,它将无法正常工作。我最终在两个域上都使用了 Laravel 5.6 ,所以我不确定100%是否适用于Laravel 5.4,但我认为应该如此。
  2. 确保您的所有子域都使用相同的APP_KEY -否则,Laravel将无法解密Cookie,返回null值,导致Laravel中的所有加密/解密都使用此应用程序密钥...
  3. SESSION_DOMAIN 。在 SESSION_DOMAIN 中,我为两个域都指向了相同的根域,如example.com。使用此设置,我可以在根域上创建一个cookie,并在两个域上正确地检索它。完成该设置后,在子域上创建cookie会强制根域也从子域cookie接收新值,并且它们将被覆盖。所以我想一切都按原始问题的要求在这里起作用。
  4. Cookie make参数-如果您要使用SESSION_DOMAIN中的子域,也可以放心地这样做。但是,您需要确保重要的是,让我们称它们为全局Cookie的定义方式有所不同。 Cookie的制作语法:

    Cookie make(string $name, string $value, int $minutes, string $path = null, string $domain = null, bool $secure = false, bool $httpOnly = true)

    所以在这里重要的是,您需要在创建该特定cookie时将其根域放在这样的示例中: return response($content)->cookie('name','value',10,null,'example.com')

结论:

  1. 通过此配置,您应该能够在子域和根域下正确访问Cookies。
  2. 您可能需要将Laravel安装更新到5.6,这将迫使您至少升级到PHP 7.1(php中的cookie也有所更改)
  3. 最后,在您的代码中,不要依赖Cookie的存在,而只依赖于它的值(我不知道您是否遇到这种情况)。

答案 2 :(得分:1)

您可以根据环境为Cookie名称设置前缀。

首先,将COOKIE_PREFIX添加到您的env文件中。

COOKIE_PREFIX=dev

然后,在设置cookie时使用它

$cookie = cookie(env('COOKIE_PREFIX', 'prod') . '_name', 'value', $minutes);

然后,像这样检索

$value = $request->cookie(env('COOKIE_PREFIX', 'prod') . '_name');