У меня новое приложение ZF3 с ACL. Теперь мне нужно, в случае несанкционированного доступа, перенаправить на страницу с ошибкой (например, 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 плачет:

Уловимая фатальная ошибка: аргумент 1, переданный Zend \ Mvc \ View \ Http \ RouteNotFoundStrategy :: detectNotFoundError (), должен быть экземпляром Zend \ Mvc \ MvcEvent, заданным экземпляром Zend \ EventManager \ Event, вызываемым в / xxxxxxx / vendor / zendframework /zend-eventmanager/src/EventManager.php в строке 271 и определен в /xxxxxxxx/vendor/zendframework/zend-mvc/src/View/Http/RouteNotFoundStrategy.php в строке 135

Где я ошибаюсь и как мне вызвать / поймать это событие?

5
Al Foиce ѫ 8 Сен 2016 в 21:31

3 ответа

Лучший ответ

Поскольку вы используете ZF3, я мог бы предложить перенести логику ACL из начальной загрузки в промежуточное ПО. Если ACL сообщает, что запрос в порядке, вы вызываете $ next, который в конечном итоге попадает на контроллер. Если это не так, вы устанавливаете статус ответа на 403 и возвращаете ответ. Проверьте доки на zend-mvc, так как у них есть пример книги рецептов для этой самой проблемы.

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

3
Jeremy Giberson 15 Сен 2016 в 17:17

Даже если это не решит проблему с событием, я решил проблему следующим образом, вернув ответ непосредственно в моем методе 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 ;
0
Al Foиce ѫ 19 Сен 2016 в 06:34

У меня такая же проблема. Триггер ошибки в вашей функции 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();
}
0
Draken 13 Июн 2017 в 07:05