Ошибка входа в систему из-за файлов cookie

8

это будет долго ...

У меня плохой случай ошибочного входа в систему из-за неправильного управления файлами cookie. Прежде всего, я управляю закрытым магазином (B2B), в котором клиенты должны войти в систему, прежде чем они смогут увидеть каталог. Каждый незарегистрированный доступ перенаправляется на страницу входа, но время от времени клиент не может войти, даже если имя пользователя и пароль указаны правильно. Я говорю «имя пользователя», потому что я использую расширение Diglin_Username и плагин StoreRestricition для достижения желаемого поведения. Случается так, что иногда я обнаруживаю два разных набора файлов cookie, оставленных Magento, и они ссылаются на два разных домена (например, .www.abc.com и .abc.com).

После прочтения этой статьи от великого Алана Шторма о раннем создании сессии и обнаружении ужасного куки-файла PHPSESSID в моем браузере я подробно исследовал проблему.

То, что я нашел, является двуличным. Сначала я поместил вызов Mage :: Log () в функцию start () класса Mage_Core_Model_Session_Abstract_Varien для регистрации различных попыток Magento начать новый сеанс и заметил, что после первого вызова Mage :: run () preDispatch () методы dispatch () и postDispatch () класса Mage_Core_Controller_Front_Action вызываются в обычной последовательности, но кажется, что при выполнении 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') (который создал бы новый сеанс), если он не может найти уже запущенный сеанс. До тех пор, пока файл cookie PHPSESSID и все готово, я подумал ...

Но не так. Теперь я избавился от cookie-файла PHPSESSID, но все равно перешел к двум различным наборам cookie (ошибочно), сохраненным в браузере. Только удалив неправильные куки, я могу успешно войти в систему, или я буду перенаправлен на страницу входа даже без сообщения. Я попытался указать домен cookie явно в конфигурации системы, но это не решило проблему.

Снова в глубине кодовой базы, и я обнаружил, что в различных местах, когда Magento устанавливает cookie, он берет домен для использования из функции getDomain () в классе Mage_Core_Model_Cookie:

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

Теперь, если вы посмотрите на страницу, которую вы получили от Magento в своем браузере, вы можете найти в разделе «head» что-то вроде этого:

<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>

и в свою очередь этот код ссылается на функцию getDomain () в классе Mage_Page_Block_Js_Cookie:

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'

и, найдя в моем браузере файлы cookie «www.abc.com» и «.www.abc.com», я подумал: «Хорошо, я настрою« .abc.com »в конфигурации системы и всегда получу« .abc.com 'печенье !! "...

Но ни за что. Теперь на моей HTML-странице я всегда получаю «.abc.com», но, тем не менее, я все же получаю ошибочно cookie «www.abc.com» и не могу войти в систему.

Я озадачен, и мой клиент начинает думать, что я не так хорош, как он думал (я тоже так думаю ...) :(

У некоторых из вас, ребята (и девочки) есть подсказка?

ОБНОВЛЕНИЕ: я видел, как кто-то связывал проблемы с сессиями и файлами cookie с использованием Varnish в качестве кеша для Magento. Поскольку я тоже использую Varnish, я попытаюсь решить эту проблему, если отключить ее.

slamarca
источник
Привет Мариус, зачем редактировать? Я нарушаю правила форума?
Сламарка
мы наблюдаем такое же поведение (логин и клиент теряют сеанс), за исключением того, что мы не можем воспроизвести проблему каким-либо образом! Это действительно усложняет любую попытку устранения неполадок, не говоря уже о решении проблемы. Как вы надежно повторили проблему? @ Сандер Мангел - Это просто вещь, я не смог воспроизвести проблему, поэтому я не могу быть уверен, как выглядят разные файлы cookie. Я был бы намного счастливее, если бы мог воспроизвести его, чтобы я мог проверить любое исправление, сделанное для решения проблемы. Я надеялся, что кто-нибудь из вас может указать мне правильное направление, как воспроизвести проблему. Спасибо!
@Жулак такая же проблема с www. и не www. печенье?
Сандер Мангель

Ответы:

8

Это статья из NovusWeb: http://www.novusweb.com/fix-for-passing-magento-session-ids/

Исправлено прохождение идентификаторов сессий Magento

Автор: Бретт Уильямс

Опубликовано 9 ноября 2011

Исправление идентификаторов сессий Magento

Мы часто используем общие SSL при создании сайтов электронной коммерции. Это удобный способ размещения нескольких магазинов без необходимости приобретения отдельных сертификатов SSL для каждого сайта. Большинство наших клиентов электронной коммерции управляют несколькими магазинами в рамках одной установки Magento или OpenCart. Недавно мы обнаружили проблему с Magento, когда идентификатор сеанса клиента не был успешно передан между его первоначальным посещением сайта и просмотром их страниц после входа в магазин в качестве зарегистрированного клиента. Magento не передавал одинаковые идентификаторы сеанса, и это означало, что клиент, который ранее вошел в систему и добавил товары в свою корзину, потеряет содержимое своей корзины после возвращения позже и входа в систему. Не очень хорошая ситуация.

Просматривая файлы cookie, созданные во время сеанса, я обнаружил, что при переходе из незащищенного домена (например, http: //) в защищенный домен (например, https: //) идентификатор сеанса успешно передавался, и новый файл cookie для защищенного домена был создан с тем же идентификатором сеанса, что и незащищенный домен. Однако, когда клиент вошел в систему, для защищенного домена был создан новый файл cookie с совершенно новым идентификатором сеанса. Magento теперь использовал более новый файл cookie, и всякий раз, когда клиент нажимал, чтобы вернуться на незащищенную страницу домена (например, страницу сведений о продукте), он больше не входил в Magento, поскольку незащищенный домен использовал идентификатор cookie / сеанса, а не новый идентификатор сессии, созданный при входе в систему. Решение состоит в том, чтобы найти место создания нового идентификатора сеанса и предотвратить его возникновение.

Итак, я начал копаться в коде, чтобы посмотреть, смогу ли я найти, где 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.

Не забудьте оставить комментарий, если вы знаете о более элегантном решении, или если вы найдете, что это работает или не работает для вас.

seanbreeden
источник
4
Для изменений, хранящихся в app/code/local/Mage/*. Перед обновлением Magento извлеките код из установщика, сравните его с измененным кодом, чтобы увидеть, не отличается ли он. В этом случае измените новую версию, которая будет установлена ​​после обновления. Нет ничего лучше, чем сохранить его при обновлении, чтобы сайт перестал работать из-за несовместимых изменений в содержимом.
Fiasco Labs
3
Согласовано. В любом случае, эта статья будет применяться только к установкам до 1.8, так как они перешли $this->renewSession();к setCustomerAsLoggedIn()функции.
seanbreeden
1
Для более текущей версии Magento, просто искать «renewSession ()» , и вы найдете его в code/core/Mage/Core/Model/Session/Abstract.phpи code/core/Mage/Admin/Model/Session.phpгде его можно закомментировать. В локальной копии модели, конечно. @FiascoLabs еще лучше, выполните правильное переопределение только той функции, которую нужно изменить, и оставьте остальную часть файла нетронутой в ядре :)
WackGet
1
это помогло нам после 3 недель попыток устранения неполадок, 4 года спустя. Проблема проявилась у нас (Magento 1.9.3.2), когда мы установили Amasty FPC и проверили нагрузку нашего сервера. т.е. невозможно войти в систему с помощью Facebook и / или обычного входа, невозможно добавить в корзину, когда сервер находится под нагрузкой. После чего даже без нагрузки проблема проявляется. Теперь, похоже, проблема устранена после того, как вы ответили. Большое спасибо @seanbreeden. Вы вдохнули новую жизнь в очень уставших разработчиков. <3
али