如何在 Symfony 2.7 中关闭用户的所有会话?

How to close all sessions for a user in Symfony 2.7?

用户更改密码后(在恢复密码操作中),我需要使连接到该用户的所有会话无效(他可能多次登录 browsers/devices)。因此,在我使用新密码将用户保存在数据库中之后,我需要关闭该用户在不同 browsers/devices 中可能处于活动状态的所有会话。我试过这个:

$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:

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);
  }
}

尝试$session->clear();

勾选documentation

根据 documentation 在默认设置中你应该已经发生了。

For example, if the username on the 2 User objects doesn't match for some reason, then the user will be logged out for security reasons. (...) Symfony also uses the username, salt, and password to verify that the User has not changed between requests

我不知道您的用户是如何配置的,但您可能需要实施 EquatableInterface

您需要跟踪该用户打开的每个会话。由于他可能登录多个 browsers/devices,他可能使用不同的会话。

一个简单的方法是将会话 ID 的引用与用户 ID 一起保存,这样您就可以获得一个用户的所有会话 ID。

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> 

在那之后,当你想撤销一个用户的所有会话时,你需要做的就是检索该用户的所有会话 ID,循环并使用

销毁它们
$session = new Session();
$session->setId($sessid);
$session->start();
$session->invalidate();

赛博卡,

这是 Symfony 安全本身的一个错误: Bug explanation to be review First Bug

所以你将不得不覆盖抽象令牌