<?php
namespace App\EventListener\ForceRoute;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
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\User\UserInterface;
abstract class AbstractForceRouteListener implements ForceRouteListenerInterface{
const MODE_REJECT_ROUTES = 'mode_reject_routes';
const MODE_ALLOW_ROUTES = 'mode_allow_routes';
protected RouterInterface $router;
protected TokenStorageInterface $tokenStorage;
protected AuthorizationCheckerInterface $authorizationChecker;
protected string $environment;
protected RequestEvent $event;
public function __construct(
RouterInterface $router,
TokenStorageInterface $tokenStorage,
AuthorizationCheckerInterface $authorizationChecker,
string $environment
){
$this->router = $router;
$this->tokenStorage = $tokenStorage;
$this->authorizationChecker = $authorizationChecker;
$this->environment = $environment;
}
public function onCheckExpired(RequestEvent $event): void {
$this->event = $event;
$request = $event->getRequest();
// Force the route if we are not using the test environments nor if the route is authorized
if(
$this->environment !== 'test'
&& !$this->isRequestedRouteAllowed($request)
&& $this->mustForceRoute($request)
){
$response = new RedirectResponse(
$this->router->generate(
$this->getRouteToForce(),
$this->getRouteParametersToForce()
)
);
$event->setResponse($response);
}
}
/**
* Get the requested route name
* @param Request $request
* @return string
*/
public function getRequestedRouteName(Request $request): string {
$pathInfo = $request->getPathInfo();
try{
$route = $this->router->match($pathInfo);
}catch(ResourceNotFoundException $exception){
return '';
}
return $route['_route'];
}
/**
* Checks if the requested route is the change password route
* @param Request $request
* @return bool
*/
public function isRequestedRouteAllowed(Request $request): bool
{
$routeName = $this->getRequestedRouteName($request);
$routeInObservedRoutes = in_array($routeName, $this->getRoutes(), true);
return $routeName === $this->getRouteToForce()
|| $this->getMode() === self::MODE_REJECT_ROUTES && !$routeInObservedRoutes
|| $this->getMode() === self::MODE_ALLOW_ROUTES && $routeInObservedRoutes
;
}
/**
* Returns the current user
* @return UserInterface
*/
public function getCurrentUser(): UserInterface {
return $this->tokenStorage->getToken()->getUser();
}
/**
* Checks if the requester is a user that is fully authenticated
* @return bool
*/
public function isRequesterAnAuthenticatedUser(): bool {
return $this->tokenStorage->getToken()
&& $this->authorizationChecker->isGranted('IS_AUTHENTICATED_FULLY');
}
/**
* @param $role
* @return bool
*/
public function isGranted($role): bool {
return $this->authorizationChecker->isGranted($role);
}
public function getMode(): string
{
return self::MODE_ALLOW_ROUTES;
}
/**
* @return array
*/
public function getRouteParametersToForce(): array
{
return [];
}
}