ACL授权失败后的ZF3重定向

时间:2016-09-08 18:31:56

标签: php zend-framework2 zend-framework3 zf3

我有一个带ACL的新ZF3应用程序。现在,在未经授权的情况下,我需要重定向到错误页面(例如403)。我认为最好的方法是发射一个事件,然后抓住它,但我失败了......

所有内容都在我的用户模块中, Module.php (摘录):

namespace User;

use Zend\Mvc\MvcEvent;
use Zend\Permissions\Acl\Acl;
use Zend\Stdlib\Response ;
use Zend\View\Model\ViewModel;
[...]

class Module implements ConfigProviderInterface
{
    [...]

    public function onBootstrap(MvcEvent $e)
    {
        // Set event to check ACL, then to handle unauthorized access
        $eventManager = $e->getApplication()->getEventManager();
        $eventManager->attach(MvcEvent::EVENT_ROUTE, array($this, 'checkProtectedRoutes'), 1);
        $eventManager->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'dispatchError'), -999);
        // Init ACL
        $this->initAcl($e);
    }

    public function initAcl(MvcEvent $e)
    {
        [...]
    }

    public function checkProtectedRoutes(MvcEvent $e)
    {
        // My access logic working fine. return if OK
        [...]

        // if authorization failed
        $e->setError('ACL_ACCESS_DENIED') ;
        $e->setParam('route', $route);
        $e->getTarget()->getEventManager()->trigger(MvcEvent::EVENT_DISPATCH_ERROR, $e);
    }

    public function dispatchError(MvcEvent $e)
    {
        // Check error type
        $error = $e->getError();
        switch ($error) {
            case 'ACL_ACCESS_DENIED' :
                // What should I do here ?

                break;
            default:
                return ;
            break;
        }
        return false ;
    }
}

但是当我的事件被触发时,我的dispatchError()方法永远不会被调用,并且ZF3会哭:

  

捕获致命错误:传递给Zend \ Mvc \ View \ Http \ RouteNotFoundStrategy :: detectNotFoundError()的参数1必须是Zend \ Mvc \ MvcEvent的实例,Zend \ EventManager \ Event的实例,在/ xxxxxxx /中调用第271行的vendor / zendframework / zend-eventmanager / src / EventManager.php,第135行的/xxxxxxxx/vendor/zendframework/zend-mvc/src/View/Http/RouteNotFoundStrategy.php中定义

我错了,我应该如何触发/捕捉此事件?

3 个答案:

答案 0 :(得分:3)

由于您正在使用ZF3,我可能会建议您将ACL逻辑移出引导程序并转移到中间件中。如果ACL说请求没问题,则调用$ next,最终到达控制器。如果不是,则将响应的状态设置为403并返回响应。查看zend-mvc上的码头,因为他们有一个关于这个问题的食谱示例。

https://docs.zendframework.com/zend-mvc/cookbook/middleware-in-listeners/

答案 1 :(得分:0)

即使它没有解决事件问题,这也是我解决问题的方法,直接在我的checkProtectedRoutes()方法中返回响应:

// Erreur 403
$e->stopPropagation();

$baseModel = new ViewModel();
$baseModel->setTemplate('403');

$resolver = new TemplateMapResolver();
$resolver->setMap( ['403' =>  __DIR__ . '/../view/error/403.phtml']);

// Render view
$renderer = new PhpRenderer();
$renderer->setResolver($resolver);
$content = $renderer->render($baseModel);
$response = $e->getResponse();
$response->setStatusCode(403);
$response->getHeaders()->addHeaderLine('Location', $e->getRequest()->getBaseUrl() . '/login');
$response->setContent($content);
return $response ;

答案 2 :(得分:0)

我遇到了同样的问题。 函数checkProtectedRoutes(MvcEvent $e)的错误触发器应使用triggerEvent方法。

//ACL Permission test        
if ( ! $auth->hasPermission( $e ) ) {
    $e->setName(MvcEvent::EVENT_DISPATCH_ERROR);
    $e->setError('ACL_ACCESS_DENIED');            
    $target = $e->getTarget();
    $res = $target->getEventManager()->triggerEvent( $e );
    return $res->last();
}