Как закрыть все сеансы для пользователя в Symfony 2.7?
После того, как пользователь изменит свой пароль (в действии восстановления пароля), мне нужно аннулировать все сеансы, подключенные к этому пользователю (он может быть зарегистрирован в нескольких браузерах/устройствах). Итак, после того, как я сохраню пользователя с новым паролем в базе данных, мне нужно закрыть все сеансы, которые могут быть активны в разных браузерах/ устройствах для этого пользователя. Я пробовал это:
$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);
Заранее спасибо!
Я добавил это своему пользователю класс:
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);
}
}
4 answers
Себкар,
Это ошибка в самой безопасности Symfony: Объяснение ошибки, подлежащее пересмотру Первая ошибка
Таким образом, вам придется переопределить абстрактный токен
Вам необходимо отслеживать каждый сеанс, открытый этим пользователем. Поскольку он может войти в систему в нескольких браузерах/устройствах, он может использовать разные сеансы.
Простой способ сделать это - сохранить ссылку на идентификатор сеанса вместе с идентификатором пользователя, чтобы вы могли получить весь идентификатор сеанса пользователя.
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 также использует имя пользователя, соль и пароль, чтобы убедиться, что Пользователь не менялся между запросами
Я не знаю, как настроен ваш пользователь, но вам может потребоваться реализовать Равнозначный интерфейс