2015-10-20 2 views
0

Я написал API, который возвращает JSON. Определенные маршруты защищены аннотацией @Security на Action Controller.Symfony2 @Security Аннотация: Отключить перенаправление, если вы не вошли в систему

Если метод is_granted() завершился неудачно, я поймаю заброшенное исключение и выдаст некоторую ошибку json с кодом статуса 403 http.

Это работает, но только если пользователь вошел в систему, но не имеет достаточных прав. Если вы не вошли в систему, пользователь перенаправляется на страницу входа в систему (вообще-то не полезен при вызове ajax).

Что я могу сделать, чтобы предотвратить перенаправление?

Я пытался добавить следующую строку в раздел security.yml access_control, но без эффекта:

access_control: 
    - { path: ^/api, role: IS_AUTHENTICATED_ANONYMOUSLY } 
+0

Вы используете '{% if is_granted ('...')%}' в своих шаблонах или '{% if app.user и is_granted ('...')%}'? –

+0

Я использую @Security ("has_role ('...')") и @Security ("is_granted (...)") непосредственно в действии контроллера – user2534194

+0

Таким образом, вы получаете доступ к выражению «Expression ... denied» Ошибка? –

ответ

0

Ok, после нескольких часов отладки я узнал, что такое поведение зашито в слушателе исключений компонента безопасности (Symfony \ Component \ Security \ Http \ Firewall \ ExceptionListener).

Так что я должен был написать свой собственный ExceptionListener, с методом onKernelException:

public function onKernelException(GetResponseForExceptionEvent $event) 
{ 
    $exception = $event->getException(); 
    do { 
     if ($exception instanceof AccessDeniedException) { 
      if(substr($event->getRequest()->server->get('PATH_INFO'), 0, 4) == '/api') { 
       $event->setException(new AjaxAccessDeniedException()); 
      } 
     } 
    } while (null !== $exception = $exception->getPrevious()); 
} 

, который проверяет, если путь начинается с/API, и бросает свой собственный AjaxAccessDeniedException. Это исключение имеет тот же код, что и AccessDeniedException, но не наследует его (поскольку в противном случае он снова будет улавливаться компонентом ExceptionListener Security). Этот я могу поймать в контроллере исключения, потому что он не попадает в другое место.

Последний шаг состоял в регистрации моего ExceptionListener как службы, но с более высоким приоритетом, чем по умолчанию.

my.exception_listener: 
    class: Acme\MyBundle\EventListener\ExceptionListener 
    arguments: [@security.context, @security.authentication.trust_resolver] 
    tags: 
     - { name: kernel.event_listener, event: kernel.exception, priority: 256 } 
0

я написал что-то очень похожее на Symfony 4.

Но в моем коде нет необходимости проверять URI запроса, потому что проверяется только главный запрос. Кроме того, код чище. AccessDeniedException из пакета Security Bundle заменяется на AccessDeniedHttpException от самого Symfony. Это приводит к реальной странице исключения 403 без потери возможностей Debug.

// PHP class: App\EventListener\RestSecurity403ExceptionListener 
namespace App\EventListener; 

use Symfony\Component\Security\Core\Exception\AccessDeniedException; 
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; 
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; 

class RestSecurity403ExceptionListener 
{ 
    public function onKernelException(GetResponseForExceptionEvent $event) 
    { 
     // only check master request 
     if (!$event->isMasterRequest()) 
      return; 

     // get variables 
     $exception = $event->getException(); 
     $request = $event->getRequest(); 

     // replace Security Bundle 403 with Symfony 403 
     if($exception instanceof AccessDeniedException) 
      throw new AccessDeniedHttpException("Symfony 403 error thrown instead of 403 error of the security bundle"); 
    } 
} 

А также добавить Exception Слушатель в вашем services.yaml:

# services.yaml 
services: 
    my.RestSecurity403ExceptionListener: 
     class: App\EventListener\RestSecurity403ExceptionListener 
     tags: 
      - { name: kernel.event_listener, event: kernel.exception, priority: 256 } 

Вот и все.

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