@ugin_root

Можно ли в symfony проверить есть ли доступ у определённой роли к url адресу?

У меня есть такая задача. Нужно после того как пользователь выходит из приложения перенаправить его на ту страницу на которой он нажал кнопу "Выход", но предварительно нужно проверить имеют ли анонимные пользователи к этой странице доступ, если не имеет то перенаправить на главную страницу.

После авторизации пользователя я могу без проблем перекинуть его на страницу из параметра или заголовка referer:
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);
}


И при этом никаких проблем не будет, ведь если страница на которой был пользователь доступна анониму, то и авторизованному пользователю она тоже будет доступна, но если я попытаюсь в контроллере выхода из приложения перенаправить на url который в referer или например в get параметре, то пользователь может попасть на страницу которая доступна только авторизованному пользователю. Т.е. перед тем как решить куда перенаправлять пользователя мне нужно проверить доступна ли url из заголовка referer для анонимного пользователя.

В идеале решение должно выглядеть примерно так:
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');
}


Но покопавшись в интернете ничего толком не нашёл, а покопавшись в исходниках symfony решения приходящие в голову слишком сложные. Хотелось бы не придумывать велосипеды.
  • Вопрос задан
  • 172 просмотра
Решения вопроса 1
BoShurik
@BoShurik Куратор тега Symfony
Symfony developer
Проще зайти с другой стороны.
- при выходе помечаем этот факт в сессии
- если после редиректа он ловит access-denied и присутствует флаг, то просто перенаправляем на главную
- убираем флаг, как только пользователь приземлился на страницу с 2XX кодом, чтоб в дальнейшем его перенапаряляло на страницу логина

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);
    }
}


На вопрос "Можно ли в symfony проверить есть ли доступ у определённой роли к url адресу?" - ответ нет, разве что вы добавите всем роутам метаданные в options и будете проверять их в обработчике LogoutEvent
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы