После подробного расследования и консультаций с некоторыми экспертами мне пришло в голову, что идея разрушения сессий неверна. Лучший вопрос – «Как заставить всех пользователей выйти из системы».
И эта проблема должна решаться не с точки зрения сеанса, которая является довольно низкоуровневым механизмом, а из компонента Security. Даже если вы удалите все данные сеанса, он будет воссоздан с помощью куки-файлов cookie со следующими запросами пользователя.
Я попытаюсь представить действительное решение этой проблемы позже.
Мне нужно реализовать функцию так называемого приложения «lockdown», поэтому мне нужен способ зарегистрировать всех пользователей из приложения Symfony 2 (закрыть все активные сеансы).
Каков наилучший способ достижения этой функциональности?
В идеале решение должно быть полностью совместимо со всеми возможными обработчиками сохранения .
Похоже, что SessionHandlerInterface
не предоставляет метода для этого.
Программный подход должен состоять в том, чтобы использовать прослушиватель сеанса и аннулировать сеанс, если существует конкретное событие, что-то вроде флага / метки времени в таблице базы данных или аналогичных.
Как описано в этой статье
Недействительность сеанса, основанного на его возрасте
use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; class SessionListener { /** * @var \Acme\DemoBundle\Service\SessionInvalidator */ protected $sessionInvalidator; function __construct($sessionInvalidator) { $this->sessionInvalidator=$sessionInvalidator; } public function onKernelRequest(GetResponseEvent $event) { if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) { return; } $session = $event->getRequest()->getSession(); $metadataBag = $session->getMetadataBag(); $lastUsed = $metadataBag->getLastUsed(); if ($lastUsed === null) { // the session was created just now return; } // "last used" is a Unix timestamp if (! $this->sessionInvalidator->checkTimestampIsValid($lastUsed)) $session->invalidate(); } }
И конфигурация:
<service id="amce_security.verify_session_listener" class="Acme\DemoBundle\EventListener\SessionListener"> <argument type="service" id="acme.session_invalidator"/> <tag name="kernel.event_listener" event="kernel.request" priority="100" method="onKernelRequest" /> </service>
Надеюсь, что эта помощь
Вы можете сохранить сеансы в базе данных по этому документу Symfony 2 Doc .
В основном вам нужно сделать следующее в вашей конфигурации:
framework: session: # ... handler_id: session.handler.pdo services: session.handler.pdo: class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler public: false arguments: - "mysql:dbname=mydatabase" - { db_username: myuser, db_password: mypassword }
Затем вы можете удалить все сеансы из базы данных!
В идеале решение должно быть полностью совместимо со всеми возможными обработчиками сохранения.
Чтобы быть полностью независимым от обработчика сохранения сеанса, я думаю, что было бы лучше, если бы вы внедрили это «внутри» сеансов самостоятельно.
Когда пользователь входит в систему, вы сохраняете текущую временную метку в своем сеансе (пользовательская отметка времени входа).
Когда вы хотите применить свое «блокирование», вы сохраняете эту текущую временную метку (временную метку блокировки) где-то в другом месте, чтобы каждый экземпляр сценария имел к ней доступ. Это может быть что-то вроде memcached / shared memory, простой файл (возможно, с помощью touch
и filemtime
) или что-то еще.
Затем на каждом запросе страницы вы проверяете, превышает ли отметка времени входа пользователя в пользовательский сеанс, чем временная метка блокировки. Если нет, пользователь вошел в систему до того, как произойдет блокировка – тогда пришло время удалить их сеанс.
И, конечно, вы отказываетесь от новых логинов, пока блокировка на месте.
Таким образом, вы можете даже разрешить пользователям продолжать свои существующие сеансы после завершения блокировки (если хотите) – если вы решили не уничтожать их сеанс, а просто запретить доступ во время блокировки. Для этого вы полностью удаляете временную метку блокировки (удалите запись memcached / shmop, удалите файл) или установите значение в далеком прошлом (fe 0).
Возможно, вы захотите реализовать исключение для блокировки на основе пользовательского уровня – пользователь-администратор, вероятно, должен будет продолжать использовать сайт (хотя бы для отключения блокировки, если ничего другого), и, по крайней мере, для этого им необходимо иметь возможность логин, независимо от блокировки).