【问题标题】:Laravel Database Sessions in Horizontally Scaled Enviornment水平扩展环境中的 Laravel 数据库会话
【发布时间】:2015-03-25 08:02:55
【问题描述】:

我在多前端/应用服务器环境中使用 Laravel(即——负载均衡器后面的两个 Web 服务器)。

我正在调试 Laravel 应用程序在向服务器发出几次请求后丢失其会话数据的问题。我们将数据库会话与单个 MySQL 数据库实例一起使用。

我注意到每次重新加载页面时,laravel_session cookie 都会发生变化。一页刷新是这样的

eyJpdiI6I-mRudUNnM0ZpQzdxYmNyaWw0d21nWFE9PSIsInZhbHVlIjoiazVDQTVuZ0IzYUg5V0l3czBxaFl6bFRrXC9aTjFmT0VBeGVDYXg1REZQM2pIS1U0U1JCSVVreHprYU44ZjhKQTU4OTVUUGxpXC9qbWZpd0FcL2NtXC9ST25B-PT0iLCJtYWMiOiJ-hZWYxNTU4MDY0ODQxODViNDRjMjQzZGE1ZDQwZDA0YzQ0ZDY1YjE3YWE3YTc3ZjcwNTg4NGE3NDhhMWMzMGU0In0

然后重新加载页面看起来像这样

eyJpdiI6I-nFjRjN1TGp0Q3Z3VmlrOG1PQlwveDF3PT0iLCJ2YWx1ZSI6IkVRYkpuWXFIVms5YnBwRXU2b1wvMFZSbW14RkVTZm8yVEpnaHRiOEhpWnlJWm9OM0JRR1wvYUI1VWhmeGYxQm0yaEFrc25PZUVcL3NSZ0RtUytzWHR3THp3-PT0iLCJtYWMiOiJ-jNTQ1YjM0MTkwZDVmM2RlMTAxYmNkMjAzMTY1NzVjMDExNTkxODAyZDM0YmQ5ZTk5NzFiNmY1YjQxYzE3ZjY1In0

- 是我添加的,以表明有些部分保持不变。

问题:

  1. 这种改变会话 ID 是标准 Laravel 行为吗?

  2. Laravel 4.2 数据库会话能否在多前端 Web 服务器环境中开箱即用?

  3. 会话实现在 Laravel 的核心中的哪个位置,以便我可以自己研究它?

回复:#1,根据ceejayozlaravel_session cookie 在每次服务器请求时都会重新加密,并且这种加密包括一些随机化——这意味着不断变化的 laravel_session 值是标准 Laravel 行为。

【问题讨论】:

  • 如果你先php artisan tinker 然后Crypt::decrypt('your session cookie contents'); 会显示会话数据吗?
  • +1 获取有用信息——如果我解密会话内容,我会得到 session_id(我使用的是数据库驱动程序,而不是 cookie 驱动程序)。你知道 Laravel 在哪里加密/解密这个 cookie 的内容吗?如果日期/时间是可以解释变化值的地穴盐的一部分。
  • 我相信 Laravel 会加密 Illuminate\Cookie\Guard 中的所有 cookie。我认为盐是随机的,但不要引用我的话。

标签: php session laravel


【解决方案1】:

这可能有很多原因,但最可能的原因是您的负载平衡器将您定向到另一台不知道您的会话 ID 的服务器,因此为您生成了一个新会话。

解决方案是使用像redis 这样的共享密钥库。 Laravel 有 native support for redis,所以不应该花费太多精力来启动和运行它,然后你的会话缓存会在你的应用程序之间共享。 Redis 非常高效且易于设置,因此您的服务器不会被它严重超载。您可能需要根据高负载下的会话数考虑升级 RAM。

当然,您也可以将会话缓存目录移动到网络共享。这可能效果不佳且浪费精力,但您的竞争对手会笑得很开心;)

编辑:还要确保两个应用具有相同的加密密钥

【讨论】:

    【解决方案2】:

    这种改变会话 ID 是标准 Laravel 行为吗?

    是的,这是标准的 Laravel 行为——Illuminate\Cookie\Guard 中间件层使用从 Illuminate\Encryption\Encrypter 类实例化的对象自动加密应用程序 cookie,其中包括 creating an initialization vector from a random source

    #File: vendor/laravel/framework/src/Illuminate/Cookie/Guard.php
    public function encrypt($value)
    {           
        $iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
        //...
        $value = base64_encode($this->padAndMcrypt($value, $iv));
        //...
    }
    

    Laravel 的 4.2 数据库会话能否在多前端 Web 服务器环境中开箱即用?

    就我所见,是的。 Laravel 的数据库会话是基于 ID 的,假设相同的应用程序和配置被发送到每个服务器,ID 可以在负载均衡器在服务器之间交换用户时存活。

    会话实现在 Laravel 的核心中的哪个位置,以便我可以自己研究它?

    Laravel 的 Session 处理是在 Session 中间件中设置的

    #File: vendor/laravel/framework/src/Illuminate/Session/Middleware.php
    

    对于好奇的人,会议在这里结束了红鲱鱼。问题是表单 URL 设置从安全 URL 发布到不安全 URL。发生这种情况时,浏览器会丢弃您的 cookie,这意味着会话 ID 已重新生成。所以,这仍然是由我们的负载平衡设置间接引起的,并且我们的猴子补丁 Request 对象没有考虑 Laravel 的 url->to() 生成的 url。我们的解决方案是将表单 URL 生成切换为使用命名为 route,并将路由配置为 https 仅在 app/routes.php

    【讨论】:

    • 嘿 Alan,我在类似设置的应用日志中看到一些围绕会话的关键冲突错误。查看 /Illuminate/Session/Store.php ,如果在两个网络服务器上以完全相同的微秒创建两个会话,这似乎是可能的。你遇到过这样的事情吗?
    • @CollinJames 我从来没有这样做过,但是阅读 uniqid 实现 (php.net/uniqid) 似乎您所描述的内容在多前端/应用服务器环境中是可能的。
    猜你喜欢
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2016-12-05
    • 2017-05-29
    相关资源
    最近更新 更多