Log user out in Symfony 2 application when "remember me" is enabled
Thanks to @nifr I was able to resolve this issue. Here's the bulletproof step-by-step guide to log user out of Symfony 2 application manually.
Warning
Symfony already implements the functionality of logging user out and deleting cookies. There is a LogoutListener
who delegates those action to couple of logout handlers: CookieClearingLogoutHandler
and SessionLogoutHandler
. I think the best course of action would be to call those handlers and not to implement such low-level logic yourself. However, I can't find a way to do this.
Solution
This solution is for Symfony 2.6. The difference is in security.token_storage
.
- Add two additional parameters to store cookie names for «session» and «remember me» to your
parameters.yml
:
# parameters.yml
parameters:
session.name: SESS
session.remember_me.name: LONGSESS
- Update your
config.yml
to use the first parameter for session name:
# config.yml
framework:
session:
name: "%session.name%"
- Update your
security.yml
to use the second parameter for remember me session name:
# security.yml
security:
firewalls:
demo_secured_area:
remember_me:
name: "%session.remember_me.name%"
- Here's the code you can use to log current user out:
You can use such code inside of a kernel event listener, if you want so.
// SomeController.php
/**
* @Route("/terminate", name="app.terminate")
*/
public function terminateAction()
{
// Logging user out.
$this->get('security.token_storage')->setToken(null);
// Invalidating the session.
$session = $this->get('request')->getSession();
$session->invalidate();
// Redirecting user to login page in the end.
$response = $this->redirectToRoute('app.login');
// Clearing the cookies.
$cookieNames = [
$this->container->getParameter('session.name'),
$this->container->getParameter('session.remember_me.name'),
];
foreach ($cookieNames as $cookieName) {
$response->headers->clearCookie($cookieName);
}
return $response;
}
Here's the implementation of kernel event listener which will force users to log out basing on entity property: Logging user out of Symfony 2 application using kernel event listener.
I hope it helps.
You may have to call the session-storage's save()
(Documentation) method explicitly.
Force the session to be saved and closed.
Further you can request to delete the session- and/or remember_me-cookies via response headers.
The session-cookie's name is configured as the container-parameter framework.session.name
and defaults to the session.name
value from your php.ini.
$cookieName = $this->container->getParameter('framework.session.name');
$response->headers->clearCookie( $cookieName );
The remember_me-cookie's name can be configured in your security
configuration.
security:
firewalls:
your_firewall:
remember_me:
name: neverforget # <- cookie-name
@Slava Fomin II
Symfony already implements the functionality of logging user out and deleting cookies. There is a LogoutListener who delegates those action to couple of logout handlers: CookieClearingLogoutHandler and SessionLogoutHandler. I think the best course of action would be to call those handlers and not to implement such low-level logic yourself. However, I can't find a way to do this.
Why not simply create a service that calls those?
I looked into Symfony\Component\Security\Http\Firewall\LogoutListener
and tested that he calls 2 services during logout (Symfony 3.2.9).
$tokenBasedRememberMeServices
by the way deletes the remember-me cookie.
<?php declare(strict_types=1);
namespace MyProject\Security\Listener;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Logout\SessionLogoutHandler;
use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices;
final class LogoutListener
{
private $sessionLogoutHandler;
private $tokenBasedRememberMeServices;
private $defaultLogoutSuccessHandler;
private $tokenStorage;
public function __construct(
SessionLogoutHandler $sessionLogoutHandler,
TokenBasedRememberMeServices $tokenBasedRememberMeServices,
DefaultLogoutSuccessHandler $defaultLogoutSuccessHandler,
TokenStorage $tokenStorage
)
{
$this->sessionLogoutHandler = $sessionLogoutHandler;
$this->tokenBasedRememberMeServices = $tokenBasedRememberMeServices;
$this->defaultLogoutSuccessHandler = $defaultLogoutSuccessHandler;
$this->tokenStorage = $tokenStorage;
}
public function logout(Request $request): void
{
$token = $this->tokenStorage->getToken();
$response = $this->defaultLogoutSuccessHandler->onLogoutSuccess($request);
$this->sessionLogoutHandler->logout($request, $response, $token);
$this->tokenBasedRememberMeServices->logout($request, $response, $token);
}
}