2015-10-20 86 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 } 

就是这样。

相关问题