Magento 1 EE v 1.14.3.x (ve CE 1.9.3.x) içinde oturum doğrulama hatası


18

Günde 400-500 ziyaretçi ve 40-50 sipariş içeren bir Magento mağazasına bakıyorum. Son zamanlarda sistem Magento EE 1.14.2.4'ten Magento EE 1.14.3.2'ye yükseltildi ve günlüklerde bazı garip istisnalar fark ettim:

exception 'Mage_Core_Model_Session_Exception' in
/var/www/.../app/code/core/Mage/Core/Model/Session/Abstract/Varien.php:418

Bu istisnayı takip ediyordum ve aşağıdaki oturum doğrulama kodu oturumu doğrulayamadığı için işten çıkarıldığını biliyorum:

class Mage_Core_Model_Session_Abstract_Varien extends Varien_Object
{
// ...
    protected function _validate()
    {
//    ...
        if ($this->useValidateSessionExpire()
            && isset($sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP])
            && $sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] < time() ) {

Bu if-bloğu Magento'dan en son sürümle dosyaya eklendi. Ve bu görünüşte bir frenleme değişikliği, daha fazla ayrıntıya bakın.

İstisna, günde bir düzine kez gibi oldukça sık görülür. ancak yukarıdaki koşulda tam anlamıyla yerine getirmediğim sürece, istisnaya neden olan koşulları yeniden oluşturamıyorum. İstisnalar çoğunlukla ürün detay sayfalarında ve bir sayfa ödeme işleminin son adımında görülür. Mağaza bir b2b mağazasıdır, kullanıcı ürün sayfasını görmek veya ödeme yapabilmek için oturum açmalıdır, oturum geçersiz kılındığında / süresi dolduğunda kullanıcının oturum açma sayfalarına yönlendirildiği anlamına gelir. Şu anda ödeme sırasında bu sorunu düzeltmek benim için daha önemli.

Kullanıcı açısından ne olur: Kullanıcı sepeti doldurur, ödeme işlemine geçer ve son adıma geçer, ardından "siparişi gönder" düğmesine basar ve hiçbir şey olmaz. Perde arkasında Magento'nun JS'si AJAX isteği gerçekleştirir ve JS, JSON'u geri almayı bekler, ancak bu hata oluşursa, giriş sayfası HTML'si döndürülür ve JavaScript tarafından ayrıştırılamaz ve hiçbir şey yapmaz. Bu kullanıcılar için çok kafa karıştırıcı.

Eh, bu tam bir kullanıcı senaryosu değil, kullanıcılarla iletişime geçtik ve bize sepeti doldurmak ve sipariş vermek arasında birkaç gün beklediklerini, bunun tam olarak ne anlama geldiğini anlamak zor olduğunu söylediler, çünkü insanlar bunu hatırlamıyor.

PHP oturum ömrü - 350000 (~ 4 gün / saniye) Çerez ömrü - 345600 (4 gün)

İşte asıl soru: ne tür kullanıcı davranışlarının istisnaya yol açtığını nasıl bulabilirim?

GÜNCELLEME Şu ana kadar yapılan taleplere göre aşağıdaki derslerde istisna olduğunu biliyorum, bu benim için maalesef hiçbir şey ifade etmiyor.

/catalogsearch/result/?q=…    Mage_Core_Model_Session
/checkout/cart/               Mage_Core_Model_Session
/checkout/onepage/saveOrder/… Mage_Rss_Model_Session
/customer/account/loginPost/  Mage_Core_Model_Session
/customer/account/loginPost/  Mage_Reports_Model_Session
/customer/account/logout/     Mage_Reports_Model_Session
/catalog/product/view/…       Mage_Reports_Model_Session
/catalog/product/view/…       Mage_Tag_Model_Session

GÜNCELLEME 2 : oturumlar dosyalarda saklanır ve bu iyi bir seçim olsun ya da olmasın PHP oturumu çöp toplayıcısı tarafından temizlenir.


Yanıtlar:


24

Bazı gelişmiş hata ayıklama, oturum izleme ve tüm bu sihir hakkında düşündükten sonra sorunu yeniden başardım ve bunun nedenini anladım. Biraz zamanlama illüstrasyonu hazırladım, aşağıda görebilirsiniz.

problem zamanı

  • kırmızı bayrak kullanıcı giriş ve oturum oluşturma anıdır
  • mavi bayrak kullanıcının katalog sayfasını açtığı an, açılmış bir kategori sayfası olduğunu varsayalım.
  • yeşil bayrak, kullanıcının siparişi gönderdiği andır ( /sales/order/save/...istek)

Nasıl çoğaltılır:

  1. Başlamadan önce: PHP oturum zaman aşımı ve Magento çerez zaman aşımı değerlerini varsayılan PHP değeri olan 1440 olarak ayarlayın.
  2. Tüm çerezlerinizi öldürün veya gizli sekmeyi açın.
  3. Magento mağazanıza gidin ve giriş yapın (bkz. Bayrak 1)
  4. Kataloğa göz atın ve sepete bazı ürünler ekleyin (Bayrak 2)
  5. Ödeme işlemini tamamlayın ve bir sipariş gönderin. Bunu yaptığınız zamanı not edin. (Bayrak 3)
  6. Kataloğa göz atın ve sepete bazı ürünler ekleyin (Bayrak 4)
  7. Macenta çerezler için yapılandırdığınız zaman aşımı süresi sona erene kadar sepet sayfanızı yenilemeye veya katalog sayfalarından geçmeye devam edin (Bayraklar 5-6). Bayrak 7 ile Bayrak 3 arasındaki sürenin çerez zaman aşımından daha uzun olması gerektiğini unutmayın.
  8. Ödeme işlemini tamamlayın ve bir sipariş gönderin (İşaret 7). Sipariş gönderimi, yukarıdaki sorumda açıklanan istisna nedeniyle başarısız olacaktır.

Sebep:

Yalnızca belirli isteklerde somutlaştırılan belirli oturumlar vardır, örn Mage_Rss_Model_Session. Katalogda gezinirken değil, yalnızca gerçek ödeme sırasında somutlaştırılır. Aynı zamanda oturum son kullanma zaman damgası yalnızca oturum başlatıldığında ayarlanır. Bu, iki ödeme arasında yeterli zaman varsa ve bu arada oturumun öldürülmediği (kullanıcının oturumu kapattığı veya çerezin süresi dolduğu için) yeni Magento kodunun bu oturumu doğrulama geçmediğini düşünecek ve bir şekilde tuhaf gelecektir. ben mi.

Nasıl düzeltilir:

Birkaç seçeneğim var:

  1. Magento buna tepki verene ve bu kodu yeniden düşünene kadar bekleyin.
  2. Bu arada bu kodu kaldırın.
  3. Sizin için bir seçenekse Magento çerez zaman aşımını 0 olarak ayarlamayı deneyin.

Nasıl anladım:

  1. Orijinal koduna aşağıdakileri ekleyerek başladım Mage_Core_Model_Session_Abstract_Varien

    Mage::log(
        sprintf(
            'useValidateSessionExpire fail "%s" "%d" "%d" "%s" "%s" "%s"',
            print_r($sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP], 1),
            time(),
            $this->_time,
            get_class($this),
            session_name(),
            session_id()
        ),
        Zend_Log::DEBUG,
        'session-validation.log',
        true
    );

    etkilenen sınıflar ve korelasyonları ve ne kadar sürenin dolduğu hakkında iyi bir fikir verdi. Ancak bu, neden olduğunu ve hangi kullanıcı işlemlerinin soruna yol açtığını açıklamıyordu.

  2. Sonra oturum verilerindeki tüm değişiklikleri nasıl izleyebileceğimi düşünmeye başladım ve bu soruya rastladım /superuser/368231/automatic-versioning-upon-file-change-modify-create-delete Vermeye karar verdim denemek gitve bir incronarada kullanmak, ancak uyguladıktan ve sanal alanda test ettikten sonra, üretimde disk alanından çok hızlı tükendiğimi fark ettim.

  3. Oturum verilerinin kodunu çözecek ve her oturum için günlükleri yazacak küçük bir PHP betiği oluşturmaya karar verdim. Bu komut dosyası tarafından çağrıldıincron

    <?php
    //log-session-data-change.php
    
    $sessionLogStoragePath = '/var/www/html/logged-session-storage/';
    
    $sessionFilePath = $argv[1];
    $sessionOperationType = $argv[2];
    $sessionFileName = basename($sessionFilePath);
    
    session_start();
    session_decode(file_get_contents($sessionFilePath));
    
    $logString = sprintf(
      '"%s","%s","%s",""' . PHP_EOL,
      date(DateTime::COOKIE),
      $sessionOperationType,
      $sessionFileName
    );
    
    if (file_exists($sessionFilePath)) {
      session_start();
      session_decode(file_get_contents($sessionFilePath));
    
      foreach ($_SESSION as $name => $data) {
        $value = '<empty>';
        if (isset($data['_session_validator_data']) && isset($data['_session_validator_data']['session_expire_timestamp'])) {
          $value = $data['_session_validator_data']['session_expire_timestamp'];
        }
        $logString .= sprintf(
          '"","","","%s","%s"' . PHP_EOL,
          $name,
          $value
        );
      }
    }
    
    file_put_contents($sessionLogStoragePath . $sessionFileName, $logString, FILE_APPEND);

    ve işte karşılık gelen incrontabgiriş

    /var/www/html/magento-doc-root/var/session IN_MODIFY,IN_CREATE,IN_DELETE,IN_MOVE /usr/bin/php /var/www/html/log-session-data-change.php $@/$# $%

    örnek çıktı

    "Wednesday, 05-Apr-2017 18:09:06 CEST","IN_MODIFY","sess_94rfglnua0phncmp98hbr3k524",""
    "","","","core","1491408665"
    "","","","customer_base","1491408665"
    "","","","catalog","1491408665"
    "","","","checkout","1491408665"
    "","","","reports","1491408494"
    "","","","store_default","1491408665"
    "","","","rss","1491408524"
    "","","","admin","1491408524"

Not:

Her ikisinin mevcut sürümleri

skin/frontend/enterprise/default/js/opcheckout.js 
src/skin/frontend/base/default/js/opcheckout.js

AJAX isteği sırasında yukarıdaki istisnayı işleyemez. Kullanıcı etkin bir şekilde oturumu kapatırken, kullanıcıya hiçbir şey göstermiyor!

PPS:

görünüşe göre Magento CE 1.9.3.x sürümleri de etkilenir, bkz. https://github.com/OpenMage/magento-mirror/blame/magento-1.9/app/code/core/Mage/Core/Model/Session/Abstract/ Varien.php

Bitki koruma ürünlerinin:

"Bu arada bu kodu kaldır" dediğimde. Aşağıdaki bloğu hariç tutmak istedim

if ($this->useValidateSessionExpire()
    && isset($sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP])
    && $sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] < time() ) {
    return false;
} else {
    $this->_data[self::VALIDATOR_KEY][self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP]
        = $validatorData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP];
}

bunu aşağıdakiler dahil birçok yolla yapabilirsiniz:

  1. Sadece bu biti dosyadan silmek
  2. Yorum yapmak
  3. Ondan önce dönüyorum
  4. $this->useValidateSessionExpire()Dönüşü doğru yapmak
  5. ...
  6. Programlama - yaratıcı olun;)

Sadece devre dışı bıraktım <Mage_Rss>ve bu sorunu düzeltti (geçici düzeltme) ve magento desteği ile bilet verdim .
Damodar Bashyal

1
@DamodarBashyal, sorunun yalnızca ödeme işlemini etkilemediğini lütfen unutmayın. Ayrıca ürün sayfalarını da etkiler, diğer bazı sayfaların da etkilenebileceğine inanıyorum. Sebep - her eflatun denetleyici eyleminde farklı oturum nesneleri kümesi başlatılır. Gerekirse daha fazla açıklama yapabilirim.
Anton Boritskiy

Sevkıyat oluştururken hata alıyordum, API ile ilgili sorunum vardı. Okuma Tamam oldu ama devre dışı bırakılana kadar yazma ile ilgili sorun oldu. Bilgi için teşekkürler.
Damodar Bashyal

9

6. Programlama - yaratıcı olun;)

Bunu düzeltmenin başka bir yolu (ve oturum doğrulamasını iyileştirmek)

ColinM @ https://github.com/OpenMage/magento-lts

Oturum kodu şu anda oturum doğrulayıcı verilerini her ad alanında depolar ve ad alanı her başlatıldığında da doğrular. Bu kötü çünkü:

  1. Oturum depolama alanında son derece verimsiz. Doğrulayıcı verileri genellikle bir ad alanı tarafından kullanılan alanın% 50'sinden fazlasını içerir ve birçok ad alanı olduğunda, bu bir ton atığa kadar ekler. Oturum depolama alanı, bu düzeltme eki ile ve Redis veya Memcached gibi bellek içi bir depolama kullanılırken çok önemli olan kesilebilir.
  2. Birden fazla ad alanı birden çok doğrulama anlamına geldiğinden ve bunların birbirinden farklı olması için iyi bir neden olmadığı için hesaplama döngülerinin yetersizliği.
  3. Aslında bazı isteklerde validator verilerinin güncellendiği ancak diğerlerinin değil güncellenen # 394 gibi hatalar oluşturur (bu nedenle farklılık gösterebilir ancak olmamalıdır). Test etmedim ama bunun da bu sorunu çözeceğine inanıyorum.
diff --git a/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php b/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php
index 45d736543..ea6b464f1 100644
--- a/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php
+++ b/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php
@@ -35,6 +35,9 @@ class Mage_Core_Model_Session_Abstract_Varien extends Varien_Object
     const VALIDATOR_SESSION_EXPIRE_TIMESTAMP    = 'session_expire_timestamp';
     const SECURE_COOKIE_CHECK_KEY               = '_secure_cookie_check';

+    /** @var bool Flag true if session validator data has already been evaluated */
+    protected static $isValidated = FALSE;
+
     /**
      * Map of session enabled hosts
      * @example array('host.name' => true)
@@ -406,16 +409,21 @@ public function getValidateHttpUserAgentSkip()
     /**
      * Validate session
      *
-     * @param string $namespace
+     * @throws Mage_Core_Model_Session_Exception
      * @return Mage_Core_Model_Session_Abstract_Varien
      */
     public function validate()
     {
-        if (!isset($this->_data[self::VALIDATOR_KEY])) {
-            $this->_data[self::VALIDATOR_KEY] = $this->getValidatorData();
+        // Backwards compatibility with legacy sessions (validator data stored per-namespace)
+        if (isset($this->_data[self::VALIDATOR_KEY])) {
+            $_SESSION[self::VALIDATOR_KEY] = $this->_data[self::VALIDATOR_KEY];
+            unset($this->_data[self::VALIDATOR_KEY]);
+        }
+        if (!isset($_SESSION[self::VALIDATOR_KEY])) {
+            $_SESSION[self::VALIDATOR_KEY] = $this->getValidatorData();
         }
         else {
-            if (!$this->_validate()) {
+            if ( ! self::$isValidated && ! $this->_validate()) {
                 $this->getCookie()->delete(session_name());
                 // throw core session exception
                 throw new Mage_Core_Model_Session_Exception('');
@@ -432,8 +440,9 @@ public function validate()
      */
     protected function _validate()
     {
-        $sessionData = $this->_data[self::VALIDATOR_KEY];
+        $sessionData = $_SESSION[self::VALIDATOR_KEY];
         $validatorData = $this->getValidatorData();
+        self::$isValidated = TRUE; // Only validate once since the validator data is the same for every namespace

         if ($this->useValidateRemoteAddr()
                 && $sessionData[self::VALIDATOR_REMOTE_ADDR_KEY] != $validatorData[self::VALIDATOR_REMOTE_ADDR_KEY]) {
@@ -444,10 +453,8 @@ protected function _validate()
             return false;
         }

-        $sessionValidateHttpXForwardedForKey = $sessionData[self::VALIDATOR_HTTP_X_FORVARDED_FOR_KEY];
-        $validatorValidateHttpXForwardedForKey = $validatorData[self::VALIDATOR_HTTP_X_FORVARDED_FOR_KEY];
         if ($this->useValidateHttpXForwardedFor()
-            && $sessionValidateHttpXForwardedForKey != $validatorValidateHttpXForwardedForKey ) {
+                && $sessionData[self::VALIDATOR_HTTP_X_FORVARDED_FOR_KEY] != $validatorData[self::VALIDATOR_HTTP_X_FORVARDED_FOR_KEY]) {
             return false;
         }
         if ($this->useValidateHttpUserAgent()

Kaynak: https://github.com/OpenMage/magento-lts/commit/de06e671c09b375605a956e100911396822e276a


Güncelleme:

web/session/use_http_x_forwarded_for optionDevre dışı bırakılan seçenek için düzeltme ... https://github.com/OpenMage/magento-lts/pull/457/commits/ec8128b4605e82406679c3cd81244ddf3878c379


1
iyi görünüyor, bunu üretimde kullanma deneyimi var mı?
Anton Boritskiy

@AntonBoritskiy Evet, bunu üretimde kullanıyorum. Mükemmel çalışıyor.
sv3n

sv3n bu çözüm yönteminin potansiyel kötü yanları var mı?
Vaishal Patel

@VaishalPatel herhangi bir potansiyel kötü tarafı varsa aslında onları görmüyorum :) Bunu üretimde kullanıyorum ve tüm oturum doğrulama sorunlarını çözdü. Herhangi bir endişem varsa bunu göndermem, ancak şüpheleriniz varsa lütfen buraya sorun: github.com/OpenMage/magento-lts/pull/406 . Belki bazı SE "artıları" da bunu gözden geçirmek için biraz zaman var?
sv3n

Üretime başlayacağım. Her iki durumda da bir çözüme doğru ilerliyor.
Vaishal Patel

1

Oturumları nasıl saklıyorsunuz? (örneğin var / session / veya DB'de veya Redis veya Memcached gibi diğer önbellek motorlarını kullanarak)

Hangisini kullanıyor olursanız olun, yazma izinlerinizin doğru olduğundan emin olun var/session/(genellikle dirs için 755 ve dosyalar için 644 olarak ayarlanır) veya Redis veya Memcache kullanıyorsanız, bağlantı ve zaman aşımı ayarlarınızın bunlar için iyi olduğundan emin olun .

Inchoo Redis için iyi bir öğretici vardır: http://inchoo.net/magento/using-redis-cache-backend-and-session-storage-in-magento/

Memcache kullanıyorsanız, bu makaleye göz atın (v1.10'a atıfta bulunur, ancak çok farklı olmamalıdır): http://www.magestore.com/magento/magento-sessions-disappearing-with-memcache-turned-on.html

Ayrıca, Vernik gibi bir şey kullanıyorsanız, geçmişte belirli sayfaların delinmesi gereken oturumlarla ilgili sorunlar vardı.

Son olarak, oturumlarınız için dosya sistemini kullanıyorsanız, içindeki <session_save>düğümü local.xml"dosyalar" yerine "db" olarak değiştirerek rahatlama bulabilirsiniz .

Bundan <session_save><![CDATA[files]]></session_save>

Buna <session_save><![CDATA[db]]></session_save>


ipucu için teşekkürler - Ben aslında nasıl oturumları saklamak hakkında soruya bilgi eklemeliydim, onları dosyalarda saklamak. Ben sadece orijinal sorunu anladım, ben bir Magento hata olduğunu düşünüyorum. Ben
bitireceğim

Harika! ... Cevabım çözüme yardımcı oldu mu?
gtr1971

gerçekten değil - benim cevabımı görmek
Anton Boritskiy

0

Anton Boritskiy'nin detayı harika. Ancak bu bloğu hariç tutmak yerine, yerel bir kopya oluşturabilirsiniz, böylece çekirdeği düzenlemez ve bloğu aşağıdaki gibi yeniden yazmazsınız:

if ($this->useValidateSessionExpire() ) {
    // If the VALIDATOR_SESSION_EXPIRE_TIMESTAMP key is not set, do it now
    if( !isset($sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP]) ) {
        // $this->_data is a reference to the $_SESSION variable so it will be automatically modified
        $this->_data[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] = time() + $this->getCookie()->getLifetime();
        return true;
    } elseif ( $sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] < time() ) {
        return false;
    }
} else {
    $this->_data[self::VALIDATOR_KEY][self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP]
        = $validatorData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP];
}

Bu, time () ile session_expire_timestamp arasındaki karşılaştırmanın yalnızca anahtar bulunduğunda yürütüldüğünü ve anahtar içermeyen bir oturum bulunduğunda (yani 1.9.3 öncesi oturum) eklendiğini garanti eder.


Yerel bir kopya eklemek ve geçersiz kılmak elbette çekirdek dosyaları değiştirmekten daha iyidir, proje oluşturma sırasında otomatik olarak uygulanan yamaların listesini dahili olarak tutarız, çünkü Magento yakın zamanda böyle birkaç hata yayınladı.
Anton Boritskiy

Aynı zamanda değişikliğinizin orijinal sorunu nasıl düzelttiğini göremiyorum, biraz daha geniş bir açıklama ekleyebilir miyim?
Anton Boritskiy

Anto Boritskiy bu liste ile iyi bir not.
Vaishal Patel

Anto Boritskiy, Yeni anahtar oturum zaman damgasının geçerliliğini kontrol etmek için kullanılır. $ sessionData $ this -> _ data'dan gelir [self :: VALIDATOR_KEY]; ancak session_expire_timestamp anahtarı oturuma yalnızca $ this-> getValidatorData () tarafından eklenir; işlevini alır ve işlev çağrısının sonunda $ this -> _ data [...] içinde saklanır. Dolayısıyla sorun, mevcut oturumlarda bu session_expire_timestamp anahtarının kullanılamamasıdır.
Vaishal Patel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.