U
U
ugin_root2020-10-30 14:28:44
symfony
ugin_root, 2020-10-30 14:28:44

Is it possible in symfony to check if a certain role has access to a url address?

I have such a task. After the user exits the application, it is necessary to redirect him to the page on which he pressed the "Exit" button, but first you need to check whether anonymous users have access to this page, if not, then redirect to the main page.

After authorizing the user, I can easily transfer him to the page from the referer parameter or header:

public function index(Request $request):RedirectResponse
{
  // ... authenticate
  
  $referer = $request->request->get('referer') ?? $request->headers->get('referer');
  
  if($referer === null){
    $this->redirectToRoute('main');
  }
  
  return new RedirectResponse($referer);
}


And at the same time, there will be no problems, because if the page on which the user was available to the anonymous user, then it will also be available to the authorized user, but if I try to redirect to the url in the application exit controller, which is in the referer or, for example, in the get parameter, then the user can get to a page that is available only to an authorized user. Those. before deciding where to redirect the user, I need to check if the url from the referer header is available to the anonymous user.

Ideally, the solution should look something like this:
public function index(
  Request $request, 
  RouteMatcherInterface $routeMatcher,
):RedirectResponse
{
  // ... exit
  
  $referer = $request->headers->get('referer');
  
  if($referer === null){
    $this->redirectToRoute('main');
  }
  
  if($routeMatcher->has($referer)){
    $router = $routeMatcher->get($referer);
    
    /**
     * $router->getName(); // string
     * $router->getParameters(); // array
     * $router->isGranted('IS_AUTHENTICATED_ANONYMOUSLY'); // bool
     */
    
    if($router->isGranted('IS_AUTHENTICATED_ANONYMOUSLY')){
      new RedirectResponse($referer);
    }
  }
  
  return $this->redirectToRoute('main');
}


But after digging around on the Internet, I didn’t really find anything, and after digging through the symfony sources, the solutions that come to mind are too complicated. I would like not to invent bicycles.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
B
BoShurik, 2020-10-30
@ugin_root

It's easier to go the other way.
- when exiting, we mark this fact in the session
- if after the redirect it catches access-denied and the flag is present, then we simply redirect to the main
one - remove the flag as soon as the user has landed on the page with 2XX code, so that in the future he will be redirected to the login page

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Event\LogoutEvent;

class LogoutRedirectSubscriber implements EventSubscriberInterface
{
    private const KEY = 'logout';

    private UrlGeneratorInterface $urlGgenerator;

    public static function getSubscribedEvents()
    {
        return [
            ExceptionEvent::class => ['onException', 2], // Before \Symfony\Component\Security\Http\Firewall\ExceptionListener
            ResponseEvent::class => 'onResponse',
            LogoutEvent::class => 'onLogout',
        ];
    }

    public function __construct(UrlGeneratorInterface $urlGgenerator)
    {
        $this->urlGgenerator = $urlGgenerator;
    }

    public function onException(ExceptionEvent $event): void
    {
        if (!$event->isMasterRequest()) {
            return;
        }
        $exception = $event->getThrowable();
        if (!$exception instanceof AccessDeniedException) {
            return;
        }
        $session = $event->getRequest()->getSession();
        if ($session->has(self::KEY)) {
            $event->setResponse(new RedirectResponse($this->urlGgenerator->generate('index')));
            $event->stopPropagation();
        }
    }

    public function onResponse(ResponseEvent $event): void
    {
        if (!$event->isMasterRequest()) {
            return;
        }
        if ($event->getResponse()->getStatusCode() >= 300) {
            return;
        }
        $session = $event->getRequest()->getSession();
        if ($session->has(self::KEY)) {
            $session->remove(self::KEY);
        }
    }

    public function onLogout(LogoutEvent $event): void
    {
        $event->getRequest()->getSession()->set(self::KEY, true);
    }
}

To the question "Is it possible in symfony to check if a certain role has access to a url address?" - the answer is no, unless you add metadata to all routes optionsand check them in the handlerLogoutEvent

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question