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

Php 如何在Symfony 2.7中关闭用户的所有会话?,php,symfony,symfony-2.7,Php,Symfony,Symfony 2.7,用户更改密码(在恢复密码操作中)后,我需要使连接到该用户的所有会话无效(他可能登录到多个浏览器/设备)。因此,在使用新密码将用户保存到数据库中后,我需要关闭该用户在不同浏览器/设备中可能处于活动状态的所有会话。我试过这个: $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); $this->get('security.token_storage')->setToken($token

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

$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);
  }
}
尝试
$session->clear()

根据默认设置检查

,您应该已经进行了检查

例如,如果两个用户对象上的用户名由于某种原因不匹配,则该用户将出于安全原因注销。(...) Symfony还使用用户名、salt和密码来验证用户在请求之间是否没有更改


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

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

一种简单的方法是将会话id的引用与用户id一起保存,这样就可以获得用户的所有sessionD

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\u login
事件,该事件将在用户每次登录时触发。然后,您可以将侦听器注册到

<service id="app_bundle.security.login_listener" class="AppBundle\Security\LoginListener.php">
    <tag name="kernel.event_subscriber" />
</service> 
塞伯卡

这是Symfony安全性本身的一个缺陷:


因此,您必须覆盖抽象令牌

Upvoted,因为我自己也不完全确定-阅读此内容是因为您希望使连接到用户的所有会话(可以登录到多个浏览器/设备)无效是的,这就是我需要的。我将重写问题,以便更清楚。会话将一个浏览器与服务器“通信”。在这种情况下,用户可以登录多个浏览器/设备。因此,我需要关闭属于该用户的所有会话。很抱歉,如果我第一次没能写出问题。很抱歉,我没能理解^^我已经按照你的建议更新了我的代码,但仍然不起作用,可能我遗漏了什么。谢谢看起来不错,不知道为什么不行。可能不值得调试,并查看
isEqualTo
是否按预期返回false。也许您可以引入一些额外的列
version
,当密码更新时,这些列也会计数并序列化它。只是尝试了一次,得到的
无法更改活动会话的ID
。例如,如果您实际登录,似乎无法使第三方会话无效。您应该创建一个新的会话对象。我们可以看到您的代码吗?在
$session=newsession()之间也是如此
$session=$request->getSession()。你可以用
session\u id($sessiond)欺骗它而不是使用
->setId():)这是一个很好的方法,但是不在数据库中存储会话(安全方面),而是在Redis中存储会话呢?另外,在redis上,您可以为保存的条目设置超时。
$session = new Session();
$session->setId($sessid);
$session->start();
$session->invalidate();