我有一个新的带有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哭:
可捕获的致命错误:参数1传递给Zend'Mvc'View'Http'RouteNotFoundStrategy::detectNotFoundError()必须是Zend'Mvc'MvcEvent的实例,给定的Zend'EventManager'Event的实例,在/xxxxxxx/vendor/zendframework/Zend - EventManager/src/EventManager.php中调用,并在/xxxxxxxx/vendor/zendframework/Zend - Mvc/src/View/Http/RouteNotFoundStrategy.php中定义,行135
哪里我错了,我应该如何触发/捕获这个事件
由于您使用的是ZF3,我可能建议将ACL逻辑从引导程序移到中间件中。如果ACL表示请求是正确的,则调用$next,它最终会到达控制器。如果不是,则将响应的状态设置为403并返回响应。查看zend-mvc上的docks,因为他们有一个解决这个问题的食谱示例。
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();
}