Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

After a user changes his password (in a recover password action), I need to invalidate all sessions connected to that user (he may be logged on multiple browsers/devices) . So, after I save the user with the new password in the database, I need to close all sessions that may be active in different browsers/devices for that user. I've tried this:

$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get('security.token_storage')->setToken($token);

Also tried:

$this->get('security.token_storage')->getToken()->setAuthenticated(false);

And this too:

$this->get('security.token_storage')->setToken(null);

Thanks in advance!

I've added this to my User 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);
  }
}
like image 934
SebCar Avatar asked Jan 07 '23 05:01

SebCar


2 Answers

You need to track every session open by that user. Since he may be logged on multiple browsers/devices, he may uses different sessions.

An easy way to do it is to save a reference of the session id together with the user id, so that you can get all the sessid of an user.

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.
         */
    }
}

then register a security.interactive_login event that will be fired every time a user log in. You can then register the listener with

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

After that, when you want revoke all the sessions for a user, all you need to do is retrieve all the session ids of that user, loop and destroy them with

$session = new Session();
$session->setId($sessid);
$session->start();
$session->invalidate();
like image 173
Federkun Avatar answered Jan 09 '23 20:01

Federkun


Sebcar,

That is a bug in the Symfony Security itself: Bug explanation to be review First Bug

So you will have to override the Abstract Token

like image 32
Rodrigo Santellan Avatar answered Jan 09 '23 20:01

Rodrigo Santellan