У меня есть новое приложение 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
Где я не прав и как мне вызвать / поймать это событие?
Поскольку вы используете ZF3, я мог бы предложить перенести логику ACL из начальной загрузки в промежуточное ПО. Если ACL говорит, что запрос в порядке, вы вызываете $ next, который в итоге попадает в контроллер. Если это не так, вы устанавливаете статус ответа 403 и возвращаете ответ. Проверьте доки на Zend-MVC, поскольку у них есть пример поваренной книги для этой самой проблемы.
https://docs.zendframework.com/zend-mvc/cookbook/middleware-in-listeners/
Даже если это не решит проблему с событием, именно так я решил проблему, возвращая ответ прямо в мой 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 ;
У меня такая же проблема.
Ошибка запуска в вашей функции 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();
}