Cookie不稳定的登录问题


8

这将是一个漫长的...

由于Cookie管理错误,我遇到了错误的登录失败错误。首先,我正在管理一家封闭式商店(B2B),客户必须先在其中登录才能看到目录。每个未注册的访问都将重定向到登录页面,但是有时,即使用户名和密码正确,客户也无法登录。我说“用户名”是因为我使用Diglin_Username扩展名和StoreRestricition插件来实现所需的行为。发生的是,有时我发现Magento留下了两组不同的Cookie,它们分别指向两个不同的域(例如,.www.abc.com和.abc.com)。

看完这篇文章早期会话实例从大艾伦风暴,并在浏览器中发现了可怕的PHPSESSID饼干我研究了一些深入的问题。

我发现是两方面的。首先,我在Mage_Core_Model_Session_Abstract_Varien类的函数start()中放置了一个Mage :: Log()调用,以记录Magento发起新会话的各种尝试,并注意到在第一次Mage :: run()调用preDispatch()之后Mage_Core_Controller_Front_Action类的,dispatch()和postDispatch()方法以通常的顺序被调用,但是似乎在postDispatch()执行时找不到由preDispatch()启动的会话,而是继续创建新会话。为此,我发现Magento 1.7.x和1.8.x版本之间的代码有所不同,我认为可以解决这个问题:

Magento 1.7.x-Mage_Core_Model_Session_Abstract_Varien类:

public function start($sessionName=null)
{
    if (isset($_SESSION)) {
        return $this;
    }
    .
    .
}

Magento 1.8.x-Mage_Core_Model_Session_Abstract_Varien类:

public function start($sessionName=null)
{
    if (isset($_SESSION) && !$this->getSkipEmptySessionCheck()) {
        return $this;
    }
    .
    .
}

我只是找不到在哪里设置SkipEmptySessionCheck属性,因此我最终以这种方式修补了Mage_Core_Controller_Front_Action类:

public function postDispatch()
{
    parent::postDispatch();
    if (!$this->getFlag('', self::FLAG_NO_START_SESSION )) {
        if (session_id()) {
            Mage::getSingleton('core/session')->setLastUrl(Mage::getUrl('*/*/*', array('_current'=>true)));
        }
    }
    return $this;
}

如果找不到无法启动的会话,则postDispatch()不会调用Mage :: getSingleton('core / session')(这将创建一个新会话)。对PHPSESSID cookie如此之久,一切都完成了,我想...

但事实并非如此。现在,我摆脱了PHPSESSID cookie,但仍然转到浏览器中保存的两个不同的cookie组(通常)。仅删除我可以成功登录的错误cookie,否则,即使没有消息,我也被重定向到登录页面。我试图在系统配置中明确声明cookie域,但这不能解决问题。

再次深入代码库,我发现在Magento设置cookie的各个地方,它使用Mage_Core_Model_Cookie类中的getDomain()函数来使用域:

public function getDomain()
{
    $domain = $this->getConfigDomain();
    if (empty($domain)) {
        $domain = $this->_getRequest()->getHttpHost();
    }
    return $domain;
}

现在,如果您在浏览器中查看从Magento获得的页面,则可以在“标题”部分中找到以下内容:

<script type="text/javascript">
//<![CDATA[
Mage.Cookies.path     = '/';
Mage.Cookies.domain   = '.www.abc.com';
//]]>
</script>

这些行来自app / design / frontend / base / default / template / page / js / cookie.phtml:

<script type="text/javascript">
//<![CDATA[
Mage.Cookies.path     = '<?php echo $this->getPath()?>';
Mage.Cookies.domain   = '<?php echo $this->getDomain()?>';
//]]>
</script>

然后此代码引用Mage_Page_Block_Js_Cookie类中的getDomain()函数:

public function getDomain()
{
    $domain = $this->getCookie()->getDomain();
    if (!empty($domain[0]) && ($domain[0] !== '.')) {
        $domain = '.'.$domain;
    }
    return $domain;
}

因此,如果我在系统配置中将Cookie域设置为“ www.abc.com”,则最终得到:

Mage.Cookies.domain   = '.www.abc.com'

并在浏览器中找到“ www.abc.com”和“ .www.abc.com” Cookie,我想,“好吧,我将在系统配置中设置“ .abc.com”,并且始终以“ .abc.com'Cookies!” ...

但是没办法。现在,在我的HTML页面中,我总是得到“ .abc.com”,但是仍然错误地获得了“ www.abc.com” Cookie,并且没有登录。

我很困惑,我的客户开始认为我不如他想的那样好(我也开始认为...):(

你们中的一些人(和女孩)有什么暗示吗?

更新: 我见过有人将会话和cookie的问题与使用Varnish作为Magento的缓存有关。当我也使用Varnish时,如果禁用它,我会尝试解决该问题。


嗨,马里乌斯,为什么要编辑?我是否违反了某些论坛规则?
slamarca 2014年

我们看到的是相同的行为(登录和客户失去会话),只是我们无法以任何方式重现该问题!这确实使任何故障排除尝试变得复杂,更不用说解决问题了。您如何可靠地复制问题?@Sander Mangel-就是这样,我无法重现该问题,因此我无法确定不同的cookie是什么样的。如果可以重现它,我会非常高兴,这样我就可以验证为解决该问题而进行的任何修复。我希望你们中的任何一个可以为我指出正确的方向,以重现该问题。谢谢!

@Zhulak与www相同的问题。和非www。饼干?
桑德·曼格

Answers:


8

这是NovusWeb的文章: http

修复传递Magento会话ID

作者:布雷特·威廉姆斯

发表于2011年11月9日

修复Magento会话ID

在构建电子商务网站时,我们经常使用共享SSL。这是托管多个商店的便捷方法,而不必为每个站点购买单独的SSL证书。我们的大多数电子商务客户都在单个Magento或OpenCart安装中管理多个商店。最近,我们发现了Magento的问题,即在以注册客户身份登录商店后,客户的会话ID在他们初次访问该网站和页面浏览之间没有成功传递。Magento没有传递相同的会话ID,这意味着以前登录并向购物车中添加项目的客户在稍后返回并登录后会丢失其购物车中的内容。

在查看会话期间创建的cookie时,我发现从不安全域(即http://)转到安全域(即https://)时,会话ID已成功传递,并且新安全域的cookie是使用与不安全域相同的会话ID创建的。但是,当客户登录时,将使用全新的会话ID为安全域创建一个新的cookie。Magento现在正在使用更新的cookie,每当客户单击以返回不安全域页面(例如,产品详细信息页面)时,由于不安全域使用其cookie /会话ID,而不是新的域,他们不再登录Magento。登录时创建的会话ID。解决方案是找到新会话ID的创建位置,并防止它发生。

因此,我开始深入研究代码,看看是否可以找到Magento在哪里创建新会话。

在app / code / core / Mage / Customer / Model / session.php中,我在177-189行(Magento CE 1.5.1)中找到了这一点:

public function login($username, $password)
{
/** @var $customer Mage_Customer_Model_Customer */
$customer = Mage::getModel('customer/customer')
->setWebsiteId(Mage::app()->getStore()->getWebsiteId());

if ($customer->authenticate($username, $password)) {
    $this->setCustomerAsLoggedIn($customer);
    $this->renewSession();
    return true;
}
return false;
}

我的解决方案是注释掉以下行:$ this-> renewSession():,以便当客户登录时Magento不会创建新会话。更改后的代码如下所示:

public function login($username, $password)
{
/** @var $customer Mage_Customer_Model_Customer */
$customer = Mage::getModel('customer/customer')
->setWebsiteId(Mage::app()->getStore()->getWebsiteId());

if ($customer->authenticate($username, $password)) {
    $this->setCustomerAsLoggedIn($customer);
    //$this->renewSession();
    return true;
}
return false;
}

到目前为止,在我们的测试中,一切工作都很好,并且在域之间保留了客户的会话。现在,在急于更改此核心文件之前,请执行以下操作:

备份数据库(在进行任何修改之前,您应该始终这样做)。构建以下目录层次结构:app / code / local / Mage / Customer / Model /。将session.php的副本放入此新目录。注释掉上面显示的相应行,然后保存文件。通过将您的修改放入app / code / local目录,您可以告诉Magento使用这些文件而不是核心文件。更重要的是,如果将来要更新Magento,可以防止所做的修改丢失。

它还提供了一种方便的方法来存储和管理代码修改,因为您只需要将修改后的文件保存在app / code / local目录中即可。

如果您知道更优雅的解决方案,或者发现该解决方案对您不起作用,请务必发表评论。


4
对于存储在中的修改app/code/local/Mage/*。在Magento升级之前,请从安装程序中提取代码,并与修改后的代码进行比较,看是否有所不同。如果是这样,请修改新版本以在升级后放置到位。由于内容的不兼容更改,没有什么像升级时那样保留下来以使站点崩溃。
Fiasco Labs 2014年

3
同意 无论如何,本文仅适用于1.8版之前的安装,因为它们已移至$this->renewSession();setCustomerAsLoggedIn()功能。
seanbreeden 2014年

1
对于最新的Magento版本,只需搜索“ renewSession()”,您将在其中找到它,code/core/Mage/Core/Model/Session/Abstract.phpcode/core/Mage/Admin/Model/Session.php在其中将其注释掉。当然,在模型的本地副本中。@FiascoLabs更好,仅对您需要修改的功能执行适当的覆盖,而将文件的其余部分完整保留在核心中:)
WackGet 2015年

1
经过4年后的3周尝试进行故障排除,这为我们提供了帮助。当我们安装Amasty FPC并对服务器进行负载测试时,该问题对我们(Magento 1.9.3.2)显而易见。即无法使用Facebook登录和/或正常登录,无法在服务器负载时添加到购物车。此后,即使没有负载,问题仍然存在。现在,按照您的回答,它现在可以像问题一样被纠正。非常感谢@seanbreeden。您为疲倦的开发人员注入了新的生命。<3
阿里
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.