2015-10-20 85 views
0

我已經編寫了一個返回JSON的API。某些路由通過Controller Action上的@Security註釋進行保護。Symfony2 @Security Annotation:在未登錄時關閉重定向

如果is_granted()方法失敗,我會捕獲拋出的異常並輸出一些帶有403 http狀態碼的錯誤json。

這是有效的,但只有當用戶登錄但沒有足夠的權限。 如果未登錄,用戶將重定向到登錄頁面(在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 ...拒絕訪問。有點錯誤? –

回答

0

好,調試小時後我發現,這種行爲是在異常監聽硬編碼的安全組件(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捕獲)。這個我可以在異常控制器中捕獲,因爲它不會在其他地方被捕獲。

最後一步是將我的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,因爲只有主請求被選中。此外,代碼更清潔。來自Security Bundle的AccessDeniedException被來自Symfony自身的AccessDeniedHttpException取代。這導致了一個真正的403異常頁面,而不會失去調試的可能性。

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

也可以增加你的services.yaml的異常監聽器:

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

就是這樣。

相關問題