如何使用 Cookie 和会话修复 Magento 登录问题

本文是与 Ktree 合作创建的。 感谢您支持使 SitePoint 成为可能的合作伙伴。

在本文中,我们将了解 Magento cookie 如何导致面向客户的前端和管理后端的登录功能出现问题、发生的原因以及应如何解决。

这也称为循环问题,因为即使用户名和密码正确,屏幕也会自行重定向到同一屏幕。

本文末尾提供了一个脚本,可以帮助检测其中的一些问题。 请根据您的需要随意使用和修改。

什么是 Cookie?

Cookie 是一段文本,Web 服务器可以将其存储在用户的硬盘驱动器上,以后也可以检索它。 Magento 在购物车和后端管理功能中使用 cookie,当无法登录到 Magento 时,它们可能是一些问题的根源。

什么是会话?

会话是服务器端的数组变量,它存储要跨多个页面使用的信息。 例如,添加到购物车的商品通常保存在会话中,当用户浏览结帐页面时,它们会从会话中读取。

会话由唯一 ID 标识。 它的名称根据编程语言而改变——在 PHP 中它被称为“PHP 会话 ID”。 您可能已经猜到了,相同的 PHP 会话 ID 需要作为 cookie 存储在客户端浏览器中才能关联。

Magento 对 Session 的存储

Magento 可以通过多个会话提供程序存储会话,这可以在 Magento 配置文件中进行配置,网址为 app/etc/local.xml. 可以在此处选择这些会话提供程序。

文件

<session_save><![CDATA[files]]></session_save>
<session_save_path>
    <![CDATA[/tmp/session]]>
</session_save_path>

数据库

允许会话将自己存储在数据库中是在 /app/etc/local.xml 通过增加 <session_save><![CDATA[db]]></session_save>.

Magento 应用程序将会话存储在 Core_session 桌子。

雷迪斯

<session_save>db</session_save>
    <redis_session>                           
             <host>127.0.0.1</host>    
        <port>6379</port>
    </redis_session>

内存缓存

session_save><![CDATA[memcache]]></session_save>
<session_save_path>
<![CDATA[tcp://localhost:11211?persistent=1&weight=2&timeout=10&retry_interval=10]]>
</session_save_path>

Magento 用法

Magento 使用两个不同的 cookie,名为“frontend”和“adminhtml”。 第一个是在浏览任何页面时创建的。 每当客户登录时,同样的 cookie 也会更新,下一个在后端用户登录时创建。您可以通过单击 Inspect Element > Application 检查是否已创建 cookie,如下图(来自 Chrome ):

通过配置管理菜单在 Magento 中配置 Cookie——系​​统 > 配置 > 常规 > Web。

问题:登录失败并重定向到登录页面

如果您没有遇到过这个问题,那么您使用 Magento 的时间还不够长!

它通常是这样发生的:当您通过输入用户名和密码登录时,您将被重定向到相同的登录页面和 URL,并且您的浏览器会附加 nonce id。 客户前端和 Magento 后端登录都会发生这种情况。

让我们看看发生这种情况的几个原因,以及我们应该如何解决这些问题。

原因 #1:Cookie 域与服务器域不匹配

假设您的 Magento 网站是 example.com Magento 中的 cookie 域配置为 xyz.com.

在这种情况下,两个 Magento cookie 都将设置 Domain Value 作为 xyz.com但为了验证会话,Magento 将考虑访问站点的域——在这种情况下 example.com. 因为它将无法找到与 example.com 域值,即使提供了有效凭据,它也会将用户重定向到登录页面。

app/code/core/Mage/Core/Model/Session/Abstract.php

登录或注销后,Magento 系统将使用以下脚本重新生成会话:

public function renewSession()
    {
        $this->getCookie()->delete($this->getSessionName());
        $this->regenerateSessionId();

        $sessionHosts = $this->getSessionHosts();
        $currentCookieDomain = $this->getCookie()->getDomain();
        if (is_array($sessionHosts)) {
            foreach (array_keys($sessionHosts) as $host) {
                // Delete cookies with the same name for parent domains
                if (strpos($currentCookieDomain, $host) > 0) {
                    $this->getCookie()->delete($this->getSessionName(), null, $host);
                }
            }
        }

        return $this;
    }

app/code/core/Mage/Core/Model/Session/Abstract/Varien.php

Magento 将使用以下方法验证每个请求的会话:

public function init($namespace, $sessionName=null)
    {
        if (!isset($_SESSION)) {
            $this->start($sessionName);
        }
        if (!isset($_SESSION[$namespace])) {
            $_SESSION[$namespace] = array();
        }

        $this->_data = &$_SESSION[$namespace];

        $this->validate();
        $this->revalidateCookie();

        return $this;
    }

当您将 Magento 实例从一个域迁移到另一个域时,例如从生产迁移到登台,并且忘记更改 cookie 域,您通常会看到这种情况。

注意:您可以运行提供的 cookieTest.php 脚本,它验证服务器 cookie 域是什么,以及在 Magento 配置中设置了什么。

解决方案:

通过配置管理菜单更改 Cookie 域。 根据屏幕截图,转到系统 > 配置 > 常规 > Web。

或者,您可以通过运行这些 SQL 查询来更改此设置。

要验证 cookie 域,请使用此选择查询来获取配置:

SELECT * FROM core_config_data WHERE path="web/cookie/cookie_domain";

执行此查询后,我们将获得结果。 验证“值”列是否与您的域相同。 如果该值与您的域不同,请更新该值。

要更新 cookie 域,请使用此查询:

UPDATE core_config_data SET VALUE = "domain.com" WHERE  path="web/cookie/cookie_domain";

原因 #2:使用了多个子域并且 Magento 的 cookie 配置不正确

假设您的网站是 example.com. 登入 example.com/admin 工作正常。

但是在你的登台/质量检查网站上,例如 staging.example.com/admin, 如果不删除所有 cookie,您将无法登录。 系统可能允许登录 staging.example.com但是当我们再次登录时 example.com/admin你的下一次点击 staging.example.com 将您踢回登录页面。 使用前端登录的客户也会遇到类似的行为。

解决方案 1

选项 A:如果您的主域和子域托管在同一台服务器上

    通过配置管理菜单更改 Cookie 域。 根据屏幕截图,转到系统 > 配置 > 常规 > Web。 查看 Cookie 域是否为 example.com, 或者 .example.com (注意前面的句点)。 如果没有,请将其设置为 .example.com.

选项 B:如果您的主域和子域托管在不同的服务器上

    通过配置管理菜单更改 Cookie 域。 根据屏幕截图,转到系统 > 配置 > 常规 > Web。 查看 Cookie 域是否为 www.example.com, 或者 .www.example.com (注意前面的句点)。 如果没有,请将其设置为 .www.example.com. 在里面 test.example.com 商店,将 Cookie 域设置为 .test.example.com 关于测试环境。

或者,通过运行这些 sql 查询来更改此设置。

要验证 cookie 域,请使用以下选择查询来获取配置:

SELECT * FROM core_config_data WHERE path = 'web/cookie/cookie_domain';

执行上述查询后,我们将得到结果。 验证“值”列是否与您的域相同。 如果它与您的域不同,请更新该值。

要更新 cookie 域,请使用以下查询:

UPDATE core_config_data SET VALUE = "domain.com" WHERE  path="web/cookie/cookie_domain";

方案二

检查您的 php.ini 文件具有与您的 Magento 配置中相同的 cookie 域——如果不将其更改为与 Magento 配置相同,如下所示:

cookie_domain = example.com

解决方案 3

这不是推荐的方法,但如果所有选项都失败,您可以尝试此代码,通过更改 adminhtml 子域的 cookie 名称。 复制文件 action.php 并将其保存在与本地相同的文件夹路径中,以便可以覆盖您的核心代码文件。

文件中有两个更改 app/code/core/Mage/Core/Controller/Varien/Action.php.

在里面 preDispatch 功能,更改这些行:

/** @var $session Mage_Core_Model_Session */ $session = Mage::getSingleton('core/session', array('name' => $this->_sessionNamespace))->start();

到:

$namespace = $this->_sessionNamespace.($_SERVER['SERVER_NAME']=='subdomain.example.com'?'_subdomain':''); /** @var $session Mage_Core_Model_Session */ $session = Mage::getSingleton('core/session', array('name' => $namespace))->start();

在函数中 setRedirectWithCookieCheck, 改变:

/** @var $session Mage_Core_Model_Session */ session = Mage::getSingleton('core/session', array('name' => $this->_sessionNamespace));

到:

$namespace = $this->_sessionNamespace.($_SERVER['SERVER_NAME']=='subdomain.example.com'?'_subdomain':''); /** @var $session Mage_Core_Model_Session */ $session = Mage::getSingleton('core/session', array('name' => $namespace));

之后,在所有文件中搜索以下文本:

Mage::getSingleton('core/session', array('name' => 'adminhtml'));`

如果发现任何匹配项,请将它们替换为:

Mage::getSingleton('core/session', array('name' => 'adminhtml'.($_SERVER['SERVER_NAME']=='subdomain.example.com'?'_subdomain':'')));

原因 3:双前端 cookie 导致间歇性登录问题

在少数情况下,系统可能会创建多个前端 cookie,从而阻止系统允许您登录。

场景 1

当您的 Magento 系统在 Magento 配置中对您的主域和子域具有相同的配置时,并且如果用户登录到两个站点,Magento 会创建两个 cookie。 一个设置了主域的“域值”,另一个设置了子域。 因此,我们将有两个前端 cookie 会话,因此我们将无法登录系统。

解决方案

将 Cookie 域设置更改为 .example.com 对于域和子域配置。

场景 2

在这种情况下,假设您 php.ini未配置 cookie 域且 Magento 域值为 example.com 已配置。 现在当用户通过登录 www.example.com系统创建一个域值为 example.com 来自 Magento 配置。 当用户注销时,Magento 将使用访问的 URL 中的域值重新生成 cookie(即 www.example.com), 因为在 php.ini 未指定 cookie 域。 请注意,如果用户登录使用 example.com 或者在中配置了 cookie 域 php.ini,不会出现任何问题。

解决方案 1

将 cookie 域添加到您的 php.ini 与您的 Magento 配置相同的文件。

session.cookie_domain = example.com

方案二

将 Cookie 域更改为 .example.com 对于域和子域配置。

注意:使用我们的 cookieTest.php 脚本来查看您是否有双前端 cookie。

原因 #4:无法创建(读取)会话 ID

Recoverable Error: session_regenerate_id(): Failed to create(read) session ID: user (path: /var/lib/php/sessions) in app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 492

这是一个您可能会在异常日志中看到的错误,并且可能只发生在 PHP7 中,因为 PHP7 会进行严格的类型检查。

解决方案是通过类型转换来更改 Magento 核心读取功能。 更多关于这里。

public function read($sessId) {
//return $data;
return (string)$data;
}

原因 #5:会话数据文件不是由您的 uid 创建的

Warning: session_start(): Session data file is not created by your uid  in app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 125

解决方案 1

如果您将会话保存在文件中,并且文件夹或文件缺少网络服务器用户权限,则会发生此错误。 所以在 nginx 的情况下,如果您的网络服务器用户是 www-data,您需要使用以下方法授予该文件夹的所有权:

sudo chown -R www-data:www-data

方案二

如果您在 Vagrant 上运行,您可能必须确定或更改文件会话路径。

解决方案 3

另一个原因是在 var/sessions 文件夹 — 删除它们并测试是否能解决问题。

注意:如果您可以选择使用不同的会话提供程序,请切换到另一个。 比如从 Redis 到文件。 清除你的 var/cache 文件夹,看看它是否有效——再一次,只在你的开发环境中尝试这个。

检测 Cookie 问题的 PHP 脚本

<?php
ini_set('display_errors', 1);
$mageFileName = getcwd() . '/app/Mage.php';
require $mageFileName;
Mage::app();
echo "<b> Server Cookie...

阅读更多

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注