Last active
September 4, 2022 17:59
-
-
Save slavafomin/4e0b70a39d1cff23af0f to your computer and use it in GitHub Desktop.
Logging user out of Symfony 2 application using kernel event listener
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Security; | |
use Symfony\Component\HttpFoundation\RedirectResponse; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Component\HttpFoundation\Session\SessionInterface; | |
use Symfony\Component\HttpKernel\Event\GetResponseEvent; | |
use Symfony\Component\Routing\RouterInterface; | |
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | |
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; | |
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; | |
use App\Model\User; | |
use App\Repository\UserRepository; | |
class ForcedLogoutListener | |
{ | |
/** @var TokenStorageInterface */ | |
protected $tokenStorage; | |
/** @var AuthorizationCheckerInterface */ | |
protected $authChecker; | |
/** @var SessionInterface */ | |
protected $session; | |
/** @var RouterInterface */ | |
protected $router; | |
/** @var UserRepository */ | |
protected $userRepository; | |
/** @var string */ | |
protected $sessionName; | |
/** @var string */ | |
protected $rememberMeSessionName; | |
/** | |
* @param TokenStorageInterface $tokenStorage | |
* @param AuthorizationCheckerInterface $authChecker | |
* @param SessionInterface $session | |
* @param RouterInterface $router | |
* @param UserRepository $userRepository | |
* @param string $sessionName | |
* @param string $rememberMeSessionName | |
*/ | |
public function __construct( | |
TokenStorageInterface $tokenStorage, | |
AuthorizationCheckerInterface $authChecker, | |
SessionInterface $session, | |
RouterInterface $router, | |
UserRepository $userRepository, | |
$sessionName, | |
$rememberMeSessionName | |
) { | |
$this->tokenStorage = $tokenStorage; | |
$this->authChecker = $authChecker; | |
$this->session = $session; | |
$this->router = $router; | |
$this->userRepository = $userRepository; | |
$this->sessionName = $sessionName; | |
$this->rememberMeSessionName = $rememberMeSessionName; | |
} | |
/** | |
* @param GetResponseEvent $event | |
* | |
* @return RedirectResponse|void | |
*/ | |
public function onKernelRequest(GetResponseEvent $event) | |
{ | |
if (!$event->isMasterRequest() || !$this->isUserLoggedIn()) { | |
return; | |
} | |
$accessToken = $this->tokenStorage->getToken(); | |
/** @var User $user */ | |
$user = $accessToken->getUser(); | |
// Forcing user to log out if required. | |
if ($user->isForceLogout()) { | |
// Logging user out. | |
$response = $this->getRedirectResponse('app.login'); | |
$this->logUserOut($response); | |
// Saving the user. | |
$user->setForceLogout(false); | |
$this->userRepository->save($user); | |
// Setting redirect response. | |
$event->setResponse($response); | |
} | |
} | |
protected function isUserLoggedIn() | |
{ | |
try { | |
return $this->authChecker->isGranted('IS_AUTHENTICATED_REMEMBERED'); | |
} catch (AuthenticationCredentialsNotFoundException $exception) { | |
// Ignoring this exception. | |
} | |
return false; | |
} | |
/** | |
* @param string $routeName | |
* | |
* @return RedirectResponse | |
*/ | |
protected function getRedirectResponse($routeName) | |
{ | |
return new RedirectResponse( | |
$this->router->generate($routeName) | |
); | |
} | |
/** | |
* @param Response $response | |
*/ | |
protected function logUserOut(Response $response = null) | |
{ | |
// Logging user out. | |
$this->tokenStorage->setToken(null); | |
// Invalidating the session. | |
$this->session->invalidate(); | |
// Clearing the cookies. | |
if (null !== $response) { | |
foreach ([ | |
$this->sessionName, | |
$this->rememberMeSessionName, | |
] as $cookieName) { | |
$response->headers->clearCookie($cookieName); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
services: | |
app.security.forced_logout_listener: | |
class: App\Security\ForcedLogoutListener | |
arguments: | |
- @security.token_storage | |
- @security.authorization_checker | |
- @session | |
- @router | |
- @app.repository.user | |
- %app.session.name% | |
- %app.session.remember_me.name% | |
tags: | |
- name: kernel.event_listener | |
event: kernel.request | |
method: onKernelRequest | |
priority: 0 | |
# Overriding Symfony's default login listener | |
security.authentication.listener.form: | |
class: WA\AppBundle\Security\UsernamePasswordFormAuthenticationListener | |
parent: security.authentication.listener.abstract | |
abstract: true | |
calls: | |
- [setUserRepository, [@app.repository.user]] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Security; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | |
use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener as BaseClass; | |
use App\Model\User; | |
use App\Repository\UserRepository; | |
class UsernamePasswordFormAuthenticationListener extends BaseClass | |
{ | |
/** @var UserRepository */ | |
protected $userRepository; | |
/** | |
* @param UserRepository $userRepository | |
*/ | |
public function setUserRepository(UserRepository $userRepository) | |
{ | |
$this->userRepository = $userRepository; | |
} | |
/** | |
* @param Request $request | |
* | |
* @return null|Response|TokenInterface | |
*/ | |
protected function attemptAuthentication(Request $request) | |
{ | |
$result = parent::attemptAuthentication($request); | |
if ($result instanceof TokenInterface) { | |
/** @var User $user */ | |
$user = $result->getUser(); | |
if ($user->isForceLogout()) { | |
// Clearing this flag. | |
$user->setForceLogout(false); | |
$this->userRepository->save($user); | |
} | |
} | |
return $result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment