Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Logging user out of Symfony 2 application using kernel event listener
<?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);
}
}
}
}
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]]
<?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