Problème de connexion erratique lié aux cookies

8

ce sera long ...

J'ai un mauvais cas d'échec de connexion erratique, en raison d'une mauvaise gestion des cookies. Tout d'abord, je gère un magasin fermé (B2B) dans lequel les clients doivent se connecter avant de pouvoir voir le catalogue. Chaque accès non enregistré est redirigé vers la page de connexion, mais de temps en temps le client ne peut pas se connecter même si le nom d'utilisateur et le mot de passe sont corrects. Je dis «nom d'utilisateur» car j'utilise l'extension Diglin_Username et le plugin StoreRestricition pour obtenir le comportement souhaité. Ce qui se passe, c'est que parfois j'ai trouvé deux ensembles de cookies différents laissés par Magento, et ils se réfèrent à deux domaines différents (.www.abc.com et .abc.com par exemple).

Après avoir lu cet article du grand Alan Storm sur l'instanciation de la première session et trouvé le redoutable cookie PHPSESSID dans mon navigateur, j'ai étudié en profondeur le problème.

Ce que j'ai trouvé est à double face. J'ai d'abord mis un appel Mage :: Log () dans la fonction start () de la classe Mage_Core_Model_Session_Abstract_Varien pour enregistrer les différentes tentatives faites par Magento pour démarrer une nouvelle session et j'ai remarqué qu'à la suite de la première invocation de Mage :: run (), le preDispatch () , les méthodes dispatch () et postDispatch () de la classe Mage_Core_Controller_Front_Action sont appelées dans la séquence habituelle mais il semble que lorsque postDispatch () s'exécute, il ne trouve pas la session démarrée par preDispatch () et procède à la création d'une nouvelle session. À cet égard, j'ai trouvé une différence dans le code entre les versions Magento 1.7.x et 1.8.x et je pense que cela pourrait peut-être résoudre le problème:

Magento 1.7.x - Classe Mage_Core_Model_Session_Abstract_Varien:

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

Magento 1.8.x - Classe Mage_Core_Model_Session_Abstract_Varien:

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

Je ne peux tout simplement pas trouver où définir la propriété SkipEmptySessionCheck, alors j'ai fini par patcher la classe Mage_Core_Controller_Front_Action de cette manière:

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

pour que postDispatch () n'appelle pas Mage :: getSingleton ('core / session') (qui aurait créé une nouvelle session) s'il ne trouve pas une session déjà démarrée. Tant de temps pour le cookie PHPSESSID et tout est fait, je pensais ...

Mais non. Maintenant, je me suis débarrassé du cookie PHPSESSID mais j'ai toujours deux ensembles de cookies différents (de manière erratique) enregistrés dans le navigateur. En supprimant uniquement les mauvais cookies, je peux me connecter avec succès, ou je suis redirigé vers la page de connexion sans même un message. J'ai essayé d'indiquer explicitement le domaine des cookies dans la configuration du système, mais cela n'a pas résolu le problème.

Profondément dans la base de code, et j'ai trouvé que dans les différents endroits où Magento définit un cookie, il prend le domaine à utiliser à partir de la fonction getDomain () dans la classe Mage_Core_Model_Cookie:

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

Maintenant, si vous regardez la page que vous obtenez de Magento dans votre navigateur, vous pouvez trouver dans la section «tête» quelque chose comme ceci:

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

Ces lignes proviennent de 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>

et à son tour, ce code fait référence à la fonction getDomain () dans la classe Mage_Page_Block_Js_Cookie:

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

Donc, si je définit le domaine des cookies dans la configuration système comme, par exemple, «www.abc.com», je me retrouve avec:

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

et en trouvant dans mon navigateur les cookies "www.abc.com" et ".www.abc.com", je me suis dit "ok, je vais mettre" .abc.com "dans la configuration du système et je finirai toujours par" Cookies .abc.com !! "...

Mais pas question. Maintenant, dans ma page HTML, je reçois toujours «.abc.com» mais néanmoins j'ai toujours un cookie «www.abc.com» et aucune connexion.

Je suis perplexe, et mon client commence à penser que je ne suis pas aussi bon qu'il le pensait (je commence à penser cela aussi ...) :(

Certains d'entre vous (et filles) ont-ils un indice?

MISE À JOUR: J'ai vu quelqu'un relier des problèmes de sessions et de cookies à l'utilisation de Varnish comme cache pour Magento. Comme j'utilise aussi Varnish, je vais essayer de le désactiver si le problème peut être résolu.

slamarca
la source
Salut Marius, pourquoi le montage? Suis-je en train de briser une règle du forum?
slamarca
nous voyons le même comportement (connexion et session client perd), sauf que nous ne pouvons reproduire le problème en aucune façon! Cela complique vraiment toute tentative de dépannage, sans parler de la résolution du problème. Comment avez-vous reproduit le problème de manière fiable? @Sander Mangel - C'est juste le problème, je n'ai pas pu reproduire le problème, donc je ne peux pas être sûr de l'apparence des différents cookies. Je serais beaucoup plus heureux si je pouvais le reproduire afin de pouvoir vérifier tout correctif apporté pour résoudre le problème. J'espérais que l'un de vous pourrait me diriger dans la bonne direction sur la façon de reproduire le problème. Merci!
@Zhulak même problème avec www. et non www. biscuits?
Sander Mangel

Réponses:

8

Ceci est un article de NovusWeb: http://www.novusweb.com/fix-for-passing-magento-session-ids/

Correction du passage des ID de session Magento

Auteur: Brett Williams

Publié le 9 novembre 2011

Correction des ID de session Magento

Nous utilisons souvent des SSL partagés lors de la création de sites de commerce électronique. C'est un moyen pratique d'héberger plusieurs magasins sans avoir à acheter des certificats SSL distincts pour chaque site. La plupart de nos clients de commerce électronique gèrent plusieurs magasins au sein d'une seule installation Magento ou OpenCart. Récemment, nous avons trouvé un problème avec Magento où l'ID de session du client n'a pas été transmis avec succès entre sa visite initiale sur le site et ses pages vues après la connexion au magasin en tant que client enregistré. Magento ne transmettait pas les mêmes identifiants de session, ce qui signifiait qu'un client qui s'était précédemment connecté et avait ajouté des articles à son panier, perdrait le contenu de son panier après être revenu plus tard et se connecter. Ce n'est pas une situation formidable.

En regardant les cookies créés pendant une session, j'ai constaté que lors du passage d'un domaine non sécurisé (par exemple, http: //) à un domaine sécurisé (par exemple, https: //), l'ID de session était passé avec succès et un nouveau le cookie pour le domaine sécurisé a été créé avec le même ID de session que le domaine non sécurisé. Cependant, lorsque le client s'est connecté, un nouveau cookie a été créé pour le domaine sécurisé avec un ID de session entièrement nouveau. Magento utilisait maintenant le nouveau cookie, et chaque fois que le client cliquait pour revenir dans une page de domaine non sécurisée (par exemple, la page de détails du produit), il n'était plus connecté à Magento car le domaine non sécurisé utilisait son cookie / ID de session, pas le nouveau ID de session créé lors de la connexion. La solution serait de trouver où le nouvel ID de session a été créé et d'empêcher que cela se produise.

J'ai donc commencé à fouiller dans le code pour voir si je pouvais trouver où Magento créait la nouvelle session.

Dans app / code / core / Mage / Customer / Model / session.php, j'ai trouvé ceci aux lignes 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;
}

Ma solution a été de commenter la ligne: $ this-> rebuildSession () :, afin que Magento ne crée pas de nouvelle session lorsque le client s'est connecté. Le code modifié ressemble à ceci:

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

Jusqu'à présent dans nos tests, tout fonctionne très bien et la session du client est conservée entre les domaines. Maintenant, avant de vous précipiter pour modifier ce fichier principal, procédez comme suit:

Sauvegardez vos bases de données (vous devez toujours le faire avant d'apporter des modifications). Créez la hiérarchie de répertoires suivante: app / code / local / Mage / Customer / Model /. Mettez une copie de session.php dans ce nouveau répertoire. Mettez en commentaire la ligne appropriée, illustrée ci-dessus, et enregistrez votre fichier. En mettant vos modifications dans le répertoire app / code / local, vous dites à Magento d'utiliser ces fichiers au lieu des fichiers de base. Plus important encore, vous évitez la perte de vos modifications si vous mettez à jour Magento à l'avenir.

Il fournit également un moyen pratique de stocker et de gérer vos modifications de code, car il vous suffit de conserver les fichiers modifiés dans le répertoire app / code / local.

Assurez-vous de laisser un commentaire si vous connaissez une solution plus élégante, ou si vous trouvez que cela fonctionne ou ne fonctionne pas pour vous.

seanbreeden
la source
4
Pour les modifications stockées dans app/code/local/Mage/*. Avant la mise à niveau de Magento, extrayez le code du programme d'installation, comparez-le avec votre code modifié pour voir s'il est différent. Si c'est le cas, modifiez la nouvelle version à mettre en place après la mise à niveau. Rien de tel que de le conserver lors de la mise à niveau pour faire basculer le site en raison de modifications incompatibles dans le contenu.
Fiasco Labs
3
D'accord. Cet article ne s'appliquerait de toute façon qu'aux installations antérieures à la version 1.8 puisqu'elles sont passées $this->renewSession();à la setCustomerAsLoggedIn()fonction.
seanbreeden
1
Pour les versions plus récentes de Magento, recherchez simplement "renouvellSession ()" et vous le trouverez dans code/core/Mage/Core/Model/Session/Abstract.phpet code/core/Mage/Admin/Model/Session.phpoù il peut être commenté. Dans une copie locale du modèle, bien sûr. @FiascoLabs encore mieux, effectuez un remplacement correct de la fonction que vous devez modifier et laissez le reste du fichier intact dans le noyau :)
WackGet
1
cela nous a aidés après 3 semaines d'essais de dépannage, 4 ans plus tard. Le problème s'est manifesté pour nous (Magento 1.9.3.2) lorsque nous avons installé Amasty FPC et testé la charge de notre serveur. c'est-à-dire impossible de se connecter avec Facebook et / ou une connexion normale, impossible d'ajouter au panier lorsque le serveur est en charge. Après quoi, même sans charge, le problème s'est manifesté. Maintenant, il semble actuellement que le problème est résolu après avoir suivi votre réponse. Merci beaucoup @seanbreeden. Vous avez insufflé une nouvelle vie à des développeurs très fatigués. <3
ali