Symfony2 @Security Annotation:未登录时关闭重定向

问题描述 投票:1回答:2

我写了一个返回JSON的API。某些路由由Controller Action上的@Security注释保护。

如果is_granted()方法失败,我会捕获抛出的异常并输出一些带有403 http状态代码的错误json。

这有效,但仅在用户登录但权限不足时才有效。如果未登录,则会将用户重定向到登录页面(在ajax调用中完全没用)。

我该怎么做才能防止重定向?

我试图将以下行添加到security.yml access_control部分,但没有效果:

access_control:
    - { path: ^/api, role: IS_AUTHENTICATED_ANONYMOUSLY }
php json symfony
2个回答
1
投票

我为Symfony 4写了一些非常相似的东西。

但是在我的代码中,不需要检查请求URI,因为只检查了主请求。此外,代码更清洁。来自安全套装的AccessDeniedException被来自Symfony本身的AccessDeniedHttpException所取代。这导致了一个真正的403 Exception页面,而不会丢失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");
    }
}

并在services.yaml中添加Exception Listener:

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

而已。


0
投票

好的,经过几个小时的调试后,我发现这个行为是在安全组件的异常监听器(Symfony \ Component \ Security \ Http \ Firewall \ ExceptionListener)中硬编码的。

所以我必须使用onKernelException方法编写自己的ExceptionListener:

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 }
© www.soinside.com 2019 - 2024. All rights reserved.