В сети куча примеров для настройки Nginx кэширования, тупая копипаста которых или же не работает вовсе или же работает, но не так как нужно (кэш файлов растёт, а эффекта = 0). Кэширование Nginx на CMS Joomla.
Мне товарищи тут почти весь моск выели и все уши прозвенели о том, что на нашем сайте, на некоторых страницах в боковой панели иногда можно видеть данные чужого профиля, хотя видящий это безобразие не был авторизирован в этом профиле - благо, что при попытке войти в него не выходит и перекидывает на страницу авторизации...
Невозможно было определить откуда ноги растут!;( Конфиг Nginx-а отшлифован и отлажен уже до такой степени, что дальше некуда - куда грешить было неясно... Начинаем копать-колупать...
Нынче рассматривается случай, когда Nginx кэширует всё как нужно, но когда некая cookie (кукиш) авторизированного пользователя истекает, то открытая ранее им страница (с данными профиля в боковой панели) посещённая снова (после истечения кукиша) кэшируется вместе с его данными профиля в боковой панели.
Т.е. мы успешно прошли авторизацию (валидность авторизации 3 часа), предварительно очистив кэш "rm -R /var/cache/nginx/pagecache/*" открыли любую статью на сайте, например "Бортовой журнал подземной лодки. О чем шептали корни.", видим статью, а в правой части экрана видим краткие данные своего профиля. Потом открываем в другом браузере, где нет авторизации, туже страницу "Бортовой журнал подземной лодки. О чем шептали корни." и всё ок. - там мы видим голую статью, которая успешно закэшировалась без чужих данных, для полной уверенности снова удаляем кэш "rm -R /var/cache/nginx/pagecache/*" и открываем туже страницу в браузере с авторизацией, а после в браузере без авторизации и опять же проблем не наблюдаем, замечательно!
ТЕПЕРЬ ВНИМАНИЕ ФОКУС: Страницу "Бортовой журнал подземной лодки. О чем шептали корни.", в том браузере где была авторизация, не закрываем и оставляем открытой, ждём когда авторизация истекает и теперь..., теперь чистим "rm -R /var/cache/nginx/pagecache/*" и сразу обновляем страницу, которая какого-то хрена кэшируется вместе с данными профиля (в правой боковой панели) уже неавторизированного пользователя - что за хрень? Парадокс?
Ну да не впадём же мы в уныние! Копаем-колупаем дальше... Такой парадокс наблюдаем в любом браузере! Хотя закэшировать то по идее должно бы страницу без данных профиля ибо кукиш то уже якобы должен то истечь. Решение о кэшировании или не кэшировании страницы nginx-ом принимается по факту наличия/отсутствия кукиша с именем activeProfile и местами неких параметров в строке запроса.
Берём браузер чистим кукиши, открываем девственную страницу и смотрим какие там кукиши устанавливаются для анонов, потом проходим авторизацию и опять смотрим кукиши которые появились новые или как изменились старые.
При попытке авторизации с пустыми логином и паролем, устанавливается кукиш так называемый Token со случайным именем (102d16838e890126ac58488e19aaad2d) и его значением (pf9g83h0ko6ap0uvul2tjekrg3). Этот Token связывает браузер пользователя с его сессией и не меняется независимо от успешности авторизации, имеет неограниченный срок жизни и удаляется только после нажатия на кнопку выхода из системы. Если после успешной авторизации изменить имя или значение Token-а, то мы сразу же потеряем доступ к своему акаунту.
Вот оно откуда растут ноги! Оказалось, что Token имеет неограниченное время жизни! После того как выдохся кукиш с именем activeProfile но не уничтожен Token связывающий браузер с сессией пользователя, то по сути сессия продолжает быть валидной и в браузер продолжают поступать данные авторизированного ранее пользователя - фича это или бага Joomla 1.5 и его компонента Jomsocial, пока не совсем ясно, но сдается мне, что это скорее бага!:), а нежели фича и на токен должно устанавливаться время жизни указываемое в переменной $lifetime конфиг. файла configuration.php.
Сей функционал, т.е. время жизни кукиша для Token-а реализуется PHP функцией session_set_cookie_params() в файле /libraries/joomla/session/session.php:
/** * Set session cookie parameters * * @access private */ function _setCookieParams() { $cookie = session_get_cookie_params(); if($this->_force_ssl) { $cookie['secure'] = true; } session_set_cookie_params( $cookie['lifetime'], $cookie['path'], $cookie['domain'], $cookie['secure'] ); }
Итак..., бага обнаружена и сейчас будет беспощадно уничтожена модификацией /libraries/joomla/session/session.php до следующей кондиции:
/** * Set session cookie parameters * * @access private */ function _setCookieParams() { $cookie = session_get_cookie_params(); if($this->_force_ssl) { $cookie['secure'] = true; } $jConfig =& JFactory::getConfig(); $lifetime = $jConfig->getValue('lifetime'); $cookie['lifetime'] = ($lifetime * 60); session_set_cookie_params( $cookie['lifetime'], $cookie['path'], $cookie['domain'], $cookie['secure'] ); }
Теперь при авторизации у нас будет выставляться одинаковое время жизни для кукишей Token-а и activeProfile. Если в session_set_cookie_params время жизни будет установлено неверно, то при авторизации мы можем получать "Invalid Token", хотя сообщение "Invalid Token" может выдаваться и в других случаях, например при одновременной попытке авторизации в фронтэнде и бакэнде сайта или при устаревшем Token-е!
Также, кроме наличия кукиша activeProfile и установки аналогичного ей времени жизни для Token-а, дополнительно нужно добавить в файл /libraries/joomla/application/application.php функцию установки/удаления некоего кукиша, например с именем "jremember", а также функцию его удаления в /plugins/system/remember.php - это нужно для тех случаев, когда при входе было отмечено "Запомнить".
Итоги
Кэширование Nginx мощная штука и капитально снижает нагрузку на бакэнд сервера, но как показывает практика его использования, единой конфигурации/рецепта Nginx кэширования не существует и для каждой системы управления, в т.ч. CMS Joomla, нужна своя конфигурация Nginx с возможным допиливанием/модифицированием файлов движка, добавлением кукишей и т.д. и т.п..
Ссылки по теме
- JFactory/getSession — Joomla! Documentation
- PHP: session_set_cookie_params - Manual
- PHP: Настройка во время выполнения - session.cookie_lifetime