Problema de login incorreto relacionado ao cookie

8

isso será longo ...

Tenho um caso grave de falha de logon incorreta, devido ao gerenciamento incorreto de cookies. Antes de tudo, estou gerenciando uma loja fechada (B2B) na qual os clientes precisam fazer login antes de poderem ver o catálogo. Todo acesso não registrado é redirecionado para a página de login, mas de vez em quando o cliente não pode fazer login, mesmo que o nome de usuário e a senha estejam corretos. Digo 'nome de usuário' porque uso a extensão Diglin_Username e o plug-in StoreRestricition para obter o comportamento desejado. O que acontece é que, às vezes, encontrei dois conjuntos diferentes de cookies deixados pelo Magento, e eles se referem a dois domínios diferentes (.abc.com e .abc.com, por exemplo).

Depois de ler este artigo do grande Alan Storm sobre a instanciação da sessão inicial e de encontrar o temido cookie PHPSESSID no meu navegador, investiguei com profundidade o problema.

O que eu encontrei é de duas caras. Primeiro, coloquei uma chamada Mage :: Log () na função start () na classe Mage_Core_Model_Session_Abstract_Varien para registrar as várias tentativas feitas pelo Magento para iniciar uma nova sessão e notei que, após a primeira chamada Mage :: run (), invoque o preDispatch () Os métodos, dispatch () e postDispatch () da classe Mage_Core_Controller_Front_Action são chamados na sequência usual, mas parece que quando o postDispatch () é executado, ele não consegue encontrar a sessão iniciada por preDispatch () e continua a criar uma nova sessão. A esse respeito, encontrei uma diferença no código entre as versões Magento 1.7.xe 1.8.x e acho que talvez possa resolver o problema:

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

Porém, não consigo encontrar onde definir a propriedade SkipEmptySessionCheck, então acabei corrigindo a classe Mage_Core_Controller_Front_Action desta maneira:

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

ter postDispatch () não chamando Mage :: getSingleton ('core / session') (que teria criado uma nova sessão) se não conseguir encontrar uma sessão já iniciada. Tanto tempo para o cookie PHPSESSID e pronto, pensei ...

Mas não é assim. Agora, me livrei do cookie PHPSESSID, mas ainda assim pego dois conjuntos diferentes de cookies (erraticamente) salvos no navegador. Excluindo apenas os cookies errados, consigo entrar com êxito ou sou redirecionado para a página de login sem nem mesmo uma mensagem. Tentei indicar o domínio do cookie explicitamente na configuração do sistema, mas isso não resolveu o problema.

Profundamente na base de código novamente, e descobri que nos vários locais em que o Magento define um cookie, é necessário o domínio para usar a partir da função getDomain () na classe Mage_Core_Model_Cookie:

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

Agora, se você olhar para a página do Magento no seu navegador, poderá encontrar na seção 'cabeça' algo como isto:

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

Essas linhas vêm 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>

e, por sua vez, esse código faz referência à função getDomain () na classe Mage_Page_Block_Js_Cookie:

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

Portanto, se eu definir o domínio do cookie na configuração do sistema como, por exemplo, 'www.abc.com', terminarei com:

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

e encontrando no meu navegador os cookies 'www.abc.com' e '.www.abc.com', pensei: "ok, configurarei '.abc.com' na configuração do sistema e sempre terminará com ' .abc.com 'cookies !! "...

Mas de jeito nenhum. Agora, na minha página HTML, sempre recebo '.abc.com', mas mesmo assim ainda recebo erraticamente um cookie 'www.abc.com' e nenhum login.

Estou perplexo, e meu cliente está começando a pensar que não sou tão bom quanto ele pensava que eu era (estou começando a pensar isso também ...) :(

Alguns de vocês (e moças) têm alguma dica?

ATUALIZAÇÃO: Eu vi alguém relacionando problemas com sessões e cookies ao uso do Varnish como cache do Magento. Como também estou usando o Varnish, tentarei desabilitá-lo. O problema pode ser resolvido.

slamarca
fonte
Oi Marius, por que a edição? Estou quebrando alguma regra do fórum?
Slamarca 6/06/2014
estamos vendo o mesmo comportamento (o login e o cliente perdem a sessão), exceto que não podemos reproduzir o problema de forma alguma! Isso realmente complica qualquer tentativa de solução de problemas, sem falar em resolver o problema. Como você replicou o problema de maneira confiável? @Sander Mangel - É isso mesmo, não consegui reproduzir o problema, então não tenho certeza de como são os diferentes cookies. Ficaria muito feliz se pudesse reproduzi-lo para verificar qualquer correção feita para resolver o problema. Eu esperava que algum de vocês pudesse me indicar a direção certa de como reproduzir o problema. Obrigado!
@Zhulak mesmo problema com www. e não www. biscoitos?
Sander Mangel

Respostas:

8

Este é um artigo da NovusWeb: http://www.novusweb.com/fix-for-passing-magento-session-ids/

Correção para passar IDs de sessão Magento

Autor: Brett Williams

Postado 9 de novembro de 2011

Corrigindo IDs de Sessão Magento

Geralmente, usamos SSLs compartilhados na criação de sites de comércio eletrônico. É uma maneira conveniente de hospedar várias lojas sem precisar comprar certificados SSL separados para cada site. A maioria dos nossos clientes de comércio eletrônico gerencia várias lojas em uma única instalação Magento ou OpenCart. Recentemente, descobrimos um problema no Magento em que o ID da sessão do cliente não estava sendo passado com êxito entre a visita inicial ao site e as visualizações de página após o logon na loja como um cliente registrado. O Magento não passava os mesmos IDs de sessão, e isso significava que um cliente que já havia feito login e adicionado itens ao carrinho, perderia o conteúdo do carrinho depois de retornar mais tarde e efetuar login. Não é uma situação ótima.

Ao examinar os cookies criados durante uma sessão, descobri que, ao passar de um domínio não seguro (por exemplo, http: //) para um domínio seguro (por exemplo, https: //), o ID da sessão estava sendo passado com êxito e um novo o cookie para o domínio seguro foi criado com o mesmo ID de sessão que o domínio não seguro. No entanto, quando o cliente efetuou login, um novo cookie foi criado para o domínio seguro com um ID de sessão totalmente novo. Agora, o Magento estava usando o cookie mais recente e, sempre que o cliente clicava para voltar para uma página de domínio não segura (por exemplo, página de detalhes do produto), não era mais possível acessar o Magento porque o domínio não seguro estava usando seu ID de cookie / sessão, não o novo ID da sessão criado no login. A solução seria descobrir onde o novo ID da sessão estava sendo criado e impedir que isso ocorresse.

Então, comecei a pesquisar no código para ver se encontrava onde o Magento estava criando a nova sessão.

Em app / code / core / Mage / Customer / Model / session.php, encontrei isso nas linhas 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;
}

Minha solução foi comentar a linha: $ this-> renewSession () :, para que o Magento não crie uma nova sessão quando o cliente estiver logado. O código alterado fica assim:

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

Até o momento em nossos testes, tudo está funcionando bem, e a sessão do cliente está sendo mantida entre domínios. Agora, antes de se apressar para alterar este arquivo principal, faça o seguinte:

Faça backup dos seus bancos de dados (você sempre deve fazer isso antes de fazer qualquer modificação). Crie a seguinte hierarquia de diretórios: app / code / local / Mage / Customer / Model /. Coloque uma cópia do session.php nesse novo diretório. Comente a linha apropriada, mostrada acima, e salve seu arquivo. Ao colocar suas modificações no diretório app / code / local, você está dizendo ao Magento para usar esses arquivos em vez dos arquivos principais. Mais importante, você está impedindo a perda de suas modificações caso atualize o Magento no futuro.

Ele também fornece uma maneira conveniente de armazenar e gerenciar suas modificações de código, pois você só precisa manter os arquivos modificados no diretório app / code / local.

Deixe um comentário se souber de uma solução mais elegante ou se achar que isso funciona ou não.

seanbreeden
fonte
4
Para modificações armazenadas em app/code/local/Mage/*. Antes da atualização do Magento, extraia o código do instalador e compare com o código modificado para ver se é diferente. Nesse caso, modifique a nova versão a ser implementada após a atualização. Nada como preservá-lo na atualização para que o site caia devido a alterações incompatíveis no conteúdo.
Fiasco Labs
3
Acordado. Este artigo se aplicaria apenas às instalações pré-1,8, de qualquer maneira, pois elas foram movidas $this->renewSession();para a setCustomerAsLoggedIn()função.
Seanbreeden
11
Para versões mais atuais do Magento, basta procurar por "renewSession ()" e você a encontrará code/core/Mage/Core/Model/Session/Abstract.phpe code/core/Mage/Admin/Model/Session.phponde pode ser comentada. Em uma cópia local do modelo, é claro. @FiascoLabs melhor ainda, realizar uma substituição adequada de apenas a função, é necessário modificar, e deixar o resto do arquivo intactos no núcleo :)
WackGet
11
isso nos ajudou após três semanas tentando solucionar problemas, quatro anos depois. O problema manifestado para nós (Magento 1.9.3.2) quando instalamos o Amasty FPC e carregamos o servidor de teste. ou seja, não é possível fazer login com o facebook e / ou login normal, não é possível adicionar ao carrinho quando o servidor está sob carga. Depois disso, mesmo sem carga, o problema se manifestava. Agora, atualmente parece que o problema foi corrigido depois de seguir sua resposta. Muito obrigado @seanbreeden. Você deu nova vida a desenvolvedores muito cansados. <3
ali