2016-12-18 3 views
1

У меня есть это в security.yml;Захват события неудачного входа в Symfony3

failure_path:  /login 

Это перенаправляет пользователя на страницу входа, если они не авторизованы при попытке доступа к определенным URL-адреса, установленные в access_control, например,

access_control: 
    - { path: ^/admin, role: ROLE_ADMIN } 

Но я не могу захватить эту перенаправление.

Я пытался использовать услугу по security.authentication.failure события, но это не работает

app.security.authentication_failure_event_listener: 
    class: MemberBundle\Event\AuthenticationListener 
    tags: 
     - { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure } 

Перенаправление все еще происходит и onAuthenticationFailure никогда не вызывается. Предположительно, потому что аутентификация явно не сработала. Пользователь просто не входит в систему и перенаправляется.

Причина в том, что я хочу дать разные ответы на основе ожидаемого формата. Например, я хочу, чтобы html-запросы переходили на страницу входа, но запросы JSON должны возвращать действительную JSON - а не страницу формы входа в HTML.

Мне кажется, что FOSRestBundle может справиться с этим, но это кажется излишним для этой относительно простой потребности. И это не веб-сайт RESTFul, поэтому мне не нужен этот пакет для этого?

Я также попробовал сервис для прослушивания Исключений, но это тоже не сработало. Я предполагаю, что перенаправление, которое происходит, не вызывает исключение?

app.exception_listener: 
    class: AppBundle\EventListener\ExceptionListener 
    tags: 
     - { name: kernel.event_listener, event: kernel.exception } 

Так как я могу всегда захватить событие перенаправления, которое происходит, когда failure_path установлен в security.yml?

+0

Не могли бы вы дать мне отзыв о моем ответе? –

+0

@gp_sflover еще нет, я еще не использовал его и ваше окончательное предложение, которое я уже пробовал, как указано в моем первоначальном вопросе –

ответ

0

Таким образом, ответ на этот вопрос заключается в тонкой информации о Symfony и AccessDeniedException.

В том, что Исключение генерируется только на основе ваших элементов управления доступом, если текущему пользователю не разрешен доступ. Это не бросается, если вы не аутентифицированы вообще.

То же самое верно для любого типа сбоя аутентификации. Его только вызываемый с каким-то аутом терпит неудачу, а не если вы просто не вошли в систему и, следовательно, не разрешены.

Так его сделали с помощью двух новых услуг

app.exception_listener: 
    class: AppBundle\EventListener\ExceptionListener 
    tags: 
     - { name: kernel.event_listener, event: kernel.exception } 

app.entry_point: 
    class: AppBundle\EventListener\EntryPoint 
    arguments: ["@router"] 

Первый делает захват AccessDeniedException, как можно было бы ожидать, когда вы лишены доступа к ресурсу.

class ExceptionListener 
{ 
    public function onKernelException(GetResponseForExceptionEvent $event) 
    { 
     $exception = $event->getException(); 
     do { 
      if ($exception instanceof AccessDeniedException) { 
       $request = $event->getRequest(); 
       if ('json' == $request->get("format") || $request->isXmlHttpRequest()) { 
        $json = new JsonResponse(["status" => 0, 'not_logged_in' => true, "msg" => "You must be logged in"]); 
        $event->setResponse($json); 
       } 
      } 
     } while (null !== $exception = $exception->getPrevious()); 
    } 
} 

Запись обслуживание точки должно быть установлено в security.yml как к

security 
    firewalls: 
     main: 
      entry_point: app.entry_point 

Этот класс обрабатывает запуск брандмауэра и обрабатывает переадресацию для аутентификации. Я проверяю наличие Exception и затем тестирую формат XHR и json и обрабатываю соответственно.

/** 
* Returns a response that directs the user to authenticate. 
* 
* This is called when an anonymous request accesses a resource that 
* requires authentication. The job of this method is to return some 
* response that "helps" the user start into the authentication process. 
* 
* Examples: 
* A) For a form login, you might redirect to the login page 
*  return new RedirectResponse('/login'); 
* B) For an API token authentication system, you return a 401 response 
*  return new Response('Auth header required', 401); 
* 
* @param Request     $request  The request that resulted in an AuthenticationException 
* @param AuthenticationException $authException The exception that started the authentication process 
* 
* @return Response 
*/ 
class EntryPoint implements AuthenticationEntryPointInterface 
{ 
    /** @var Router */ 
    protected $router; 

    public function __construct(Router $router) 
    { 
     $this->router = $router; 
    } 

    public function start(Request $request, AuthenticationException $authException = null) { 
     if($authException) { 
      if('json' == $request->get("format") || $request->isXmlHttpRequest()) { 
       return new JsonResponse(["status" => 0, 'not_logged_in' => true, "msg" => "You must be logged in"]); 
      } 
     } 

     return new RedirectResponse($this->router->generate("fos_user_security_login")); 
    } 
} 
1

My Tip (также для будущего) - это «Create a Custom Authentication System with Guard». Более простой и гибкий/настраиваемый для обработки этого материала (особенно, если это немного сложно с помощью многих аутентификаторов, таких как facebook, twitter и т. Д.) И с помощью запомнить меня вариант активированный ...)

Но ... как показано в SecurityBundle Configuration ("security") вы можете установить параметр failure_handler для каждой системы авторизации в этом брандмауэре:.

security: 
    firewalls: 
     your_firewall_name: 
      form_login: 
       failure_handler: your_custom_failure_handler_service_name <-- THIS ONE 

Затем вы можете создать инъекционную службу необходимые зависимости для обработки необходимого вам материала и возврата другой базы ответов d в формате запроса.

ПРИМЕЧАНИЕ: Я не уверен, что вы можете достичь этого, также создавая слушателя для Security authentication event failure, но вы можете попробовать.

+0

Было полезно, но не совсем понял меня. Я опубликовал новый ответ. –

Смежные вопросы