После того, как пользователь изменит свой пароль (в случае действия восстановления пароля), мне необходимо аннулировать все сеансы, подключенные к этому пользователю (он может быть зарегистрирован на нескольких браузерах / устройствах). Итак, после сохранения пользователя с новым паролем в базе данных мне нужно закрыть все сеансы, которые могут быть активны в разных браузерах / устройствах для этого пользователя. Я пробовал это:
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); $this->get('security.token_storage')->setToken($token);
Также попробовали:
$this->get('security.token_storage')->getToken()->setAuthenticated(false);
И это тоже:
$this->get('security.token_storage')->setToken(null);
Заранее спасибо!
Я добавил это в свой класс User:
class User implements UserInterface, EquatableInterface, \Serializable{ // properties and other methods public function isEqualTo(UserInterface $user){ if ($user->getPassword() !== $this->getPassword()){ return false; } if ($user->getEmail() !== $this->getEmail()){ return false; } if ($user->getRoles() !== $this->getRoles()){ return false; } return true; } /** @see \Serializable::serialize() */ public function serialize() { return serialize(array( $this->id, $this->email, $this->password, // see section on salt below // $this->salt, )); } /** @see \Serializable::unserialize() */ public function unserialize($serialized) { list ( $this->id, $this->email, $this->password, // see section on salt below // $this->salt ) = unserialize($serialized); } }
Sebcar,
Это ошибка в Symfony Security: описание ошибки для обзора First Bug
Таким образом, вам придется переопределить абстрактный токен
Вам нужно отслеживать каждую сессию, открытую этим пользователем. Поскольку он может быть зарегистрирован на нескольких браузерах / устройствах, он может использовать разные сеансы.
Легкий способ сделать это – сохранить ссылку идентификатора сеанса вместе с идентификатором пользователя, чтобы вы могли получить все sessid пользователя.
namespace AppBundle\Security; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; class LoginListener implements EventSubscriberInterface { public static function getSubscribedEvents() { return array( SecurityEvents::INTERACTIVE_LOGIN => 'onSecurityInteractiveLogin', ); } public function onSecurityInteractiveLogin(InteractiveLoginEvent $event) { $user = $event->getAuthenticationToken()->getUser(); $session = $event->getRequest()->getSession(); /* * Save $user->getId() and $session->getId() somewhere * or update it if already exists. */ } }
затем зарегистрируйте событие security.interactive_login
которое будет запущено при каждом входе пользователя в систему. Затем вы можете зарегистрировать слушателя с помощью
<service id="app_bundle.security.login_listener" class="AppBundle\Security\LoginListener.php"> <tag name="kernel.event_subscriber" /> </service>
После этого, когда вы хотите отменить все сеансы для пользователя, все, что вам нужно сделать, это получить все идентификаторы сеанса этого пользователя, выполнить цикл и уничтожить их с помощью
$session = new Session(); $session->setId($sessid); $session->start(); $session->invalidate();
Согласно документации по умолчанию, вы должны это уже произойти.
Например, если имя пользователя из 2 пользовательских объектов по какой-либо причине не соответствует, пользователь будет выведен из системы по соображениям безопасности. (…) Symfony также использует имя пользователя, соль и пароль, чтобы убедиться, что Пользователь не изменился между запросами
Я не знаю, как настроен ваш пользователь, но вам может потребоваться реализовать EquatableInterface
Попробуйте $session->clear();
Проверьте документацию