Подтвердить что ты не робот

Как перенаправить на другой URL-адрес на основе ролей в symfony 2

У меня есть одна страница входа на сайт. У меня 4 разных пользователя, и я хочу, чтобы при их входе они переходили на другую страницу в зависимости от назначенной роли.

Есть ли способ?

4b9b3361

Ответ 1

Один из способов решения этой проблемы - использовать прослушиватель событий в событии security.interactive_login. В этом случае я просто присоединяю другого слушателя в этом прослушивателе событий, чтобы он срабатывал при ответе. Это позволяет проверить подлинность, но все же выполнить перенаправление после завершения.

<service id="sotb_core.listener.login" class="SOTB\CoreBundle\EventListener\SecurityListener" scope="request">
    <tag name="kernel.event_listener" event="security.interactive_login" method="onSecurityInteractiveLogin"/>
    <argument type="service" id="router"/>
    <argument type="service" id="security.context"/>
    <argument type="service" id="event_dispatcher"/>
</service>

И класс...

class SecurityListener
{
    protected $router;
    protected $security;
    protected $dispatcher;

    public function __construct(Router $router, SecurityContext $security, EventDispatcher $dispatcher)
    {
        $this->router = $router;
        $this->security = $security;
        $this->dispatcher = $dispatcher;
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
        $this->dispatcher->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse'));
    }

    public function onKernelResponse(FilterResponseEvent $event)
    {
        if ($this->security->isGranted('ROLE_TEAM')) {
            $response = new RedirectResponse($this->router->generate('team_homepage'));
        } elseif ($this->security->isGranted('ROLE_VENDOR')) {
            $response = new RedirectResponse($this->router->generate('vendor_homepage'));
        } else {
            $response = new RedirectResponse($this->router->generate('homepage'));
        }

        $event->setResponse($response);
    }
}

Ответ 2

Для Symfony >= 2.6 теперь будет:

<?php

namespace CommonBundle\Listener;

use Monolog\Logger;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

class LoginListener
{
    /** @var Router */
    protected $router;

    /** @var TokenStorage */
    protected $token;

    /** @var EventDispatcherInterface */
    protected $dispatcher;

    /** @var Logger */
    protected $logger;

    /**
     * @param Router $router
     * @param TokenStorage $token
     * @param EventDispatcherInterface $dispatcher
     * @param Logger $logger
     */
    public function __construct(Router $router, TokenStorage $token, EventDispatcherInterface $dispatcher, Logger $logger)
    {
        $this->router       = $router;
        $this->token        = $token;
        $this->dispatcher   = $dispatcher;
        $this->logger       = $logger;
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
        $this->dispatcher->addListener(KernelEvents::RESPONSE, [$this, 'onKernelResponse']);
    }

    public function onKernelResponse(FilterResponseEvent $event)
    {
        $roles = $this->token->getToken()->getRoles();

        $rolesTab = array_map(function($role){
            return $role->getRole();
        }, $roles);

        $this->logger->info(var_export($rolesTab, true));

        if (in_array('ROLE_ADMIN', $rolesTab) || in_array('ROLE_SUPER_ADMIN', $rolesTab)) {
            $route = $this->router->generate('backend_homepage');
        } elseif (in_array('ROLE_CLIENT', $rolesTab)) {
            $route = $this->router->generate('frontend_homepage');
        } else {
            $route = $this->router->generate('portal_homepage');
        }

        $event->getResponse()->headers->set('Location', $route);
    }
}

И services.yml

services:
common.listener.login:
    class: CommonBundle\Listener\LoginListener
    arguments: [@router, @security.token_storage, @event_dispatcher, @logger]
    scope: request
    tags:
        - { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }

Ответ 3

Я использовал Mdrollette ответ, но это решение имеет большой недостаток, вы полностью переопределяете исходный отклик symfony и, делая это, удаляете куки файл, который был указан в заголовке symfony.

Мое решение состояло в том, чтобы изменить OnKernelResponse следующим образом:

public function onKernelResponse(FilterResponseEvent $event)
{
    if ($this->security->isGranted('ROLE_TEAM')) {
        $event->getResponse()->headers->set('Location', $this->router->generate('team_homepage'));    
    } elseif ($this->security->isGranted('ROLE_VENDOR')) {
        $event->getResponse()->headers->set('Location', $this->router->generate('vendor_homepage'));
    } else {
        $event->getResponse()->headers->set('Location', $this->router->generate('homepage'));
    }
}

Таким образом, вы остаетесь помнить, что печенье не повреждено.

Ответ 4

Протестировано в Symfony 3.1

Вы также можете установить путь по умолчанию после успешного входа в систему для всех пользователей в файле seciurity.yml следующим образом:

[Config/seciurity.yml]

...

firewalls:
    # disables authentication for assets and the profiler, adapt it according to your needs
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        pattern: /.*
        form_login:
            login_path: /login
            check_path: /login_check
            default_target_path: /login/redirect <<<<<<<<<<<<<<<<<<<<<<<<<
        logout:
            path: /logout
            target: /
        security: true
        anonymous: ~
...

, а затем в этом месте делают простое перенаправление на основе роли пользователя. Очень прямо. Некоторые говорят, что самый простой способ - это всегда лучший способ. Вы решаете:)

[SomeBundle/контроллер/SomeController.php]

/**
 * Redirect users after login based on the granted ROLE
 * @Route("/login/redirect", name="_login_redirect")
 */
public function loginRedirectAction(Request $request)
{

    if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY'))
    {
        return $this->redirectToRoute('_login');
        // throw $this->createAccessDeniedException();
    }

    if($this->get('security.authorization_checker')->isGranted('ROLE_ADMIN'))
    {
        return $this->redirectToRoute('_admin_panel');
    }
    else if($this->get('security.authorization_checker')->isGranted('ROLE_USER'))
    {
        return $this->redirectToRoute('_user_panel');
    }
    else
    {
        return $this->redirectToRoute('_login');
    }

}

Работает как шарм, но имейте в виду, чтобы всегда проверять наиболее ограниченные роли вниз, если у вашего ROLE_ADMIN также есть привилегии ROLE_USER и т.д....

Ответ 5

Если вы ищете более простой ответ, чем @MDrollette, вы можете поместить аналогичный блок переадресации в контроллер своей страницы успеха входа.

Ответ 6

Для тестирования, если вы хотите сохранить исходный ответ, вы также можете просто скопировать заголовки. Метод clone объекта Redirect копирует только заголовки.

public function onKernelResponse(FilterResponseEvent $event)
{
    if ($this->security->isGranted('ROLE_TEAM')) {
        $response = new RedirectResponse($this->router->generate('team_homepage'));
    } elseif ($this->security->isGranted('ROLE_VENDOR')) {
        $response = new RedirectResponse($this->router->generate('vendor_homepage'));
    } else {
        $response = new RedirectResponse($this->router->generate('homepage'));
    }

    $response->headers = $response->headers + $event->getResponse()->headers;

    $event->setResponse($response);
}