У меня есть одна страница входа на сайт. У меня 4 разных пользователя, и я хочу, чтобы при входе в систему они переходили на другую страницу в зависимости от назначенной им роли.
Там в любом случае?
Один из способов решения этой проблемы – использовать прослушиватель событий в событии 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); } }
Для 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 }
Я использовал 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')); } }
Таким образом, вы остаетесь помнить меня печенье неповрежденным.
Протестировано в 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'); } }
Работает как прелесть, но держит в maind, чтобы всегда проверять наиболее ограниченные ролевые слова, если у вашего ROLE_ADMIN есть, например, привилегии ROLE_USER и так далее …
Если вы ищете более простой ответ, чем @MDrollette, вы можете поместить аналогичный блок перенаправления в контроллер своей страницы успеха в вашем аккаунте.
Для тестирования, если вы хотите сохранить исходный ответ, вы также можете просто скопировать заголовки. Метод 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); }