当不允许用户访问特定资源时,我需要将用户重定向到名为view/error/403.phtml
的模块的Module.php
内的错误页面(Admin
)。我一直在寻找解决方案,但到目前为止还没有成功。我找到的最好的是this question,接受的答案对我不起作用(我目前无法为链接的问题添加评论,因为我没有所需的声誉级别) - 页面显示为如果根本没有重定向,则允许用户访问它。我试图用简单的die;
替换重定向代码来测试isAllowed()
是否正常工作,并且它正确显示了空白页面,因此问题在于重定向本身。
Module.php
中的相关代码是:
public function onBootstrap(MvcEvent $e)
{
$this->initAcl($e);
$eventManager = $e->getApplication()->getEventManager();
$eventManager->attach('route', array($this, 'checkAcl'));
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
}
public function checkAcl(MvcEvent $e)
{
// ...
if (!$this->acl->isAllowed($userRole, $controller, $privilege))
{
$response = $e->getResponse();
$response->setHeaders($response->getHeaders()->addHeaderLine('Location', $e->getRequest()->getBaseurl() . '/error/403'));
$response->setStatusCode(403);
$response->sendHeaders();
}
// ...
}
module.config.php
'view_manager' => array(
'display_exceptions' => true,
'exception_template' => 'error/403',
'template_map' => array(
'layout/layout' => __DIR__ . '/../view/layout/admin_layout.phtml',
'error/403' => __DIR__ . '/../view/error/403.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
'Admin' => __DIR__ . '/../view',
),
'strategies' => array(
'ViewJsonStrategy',
),
),
如果我添加行
throw new \Exception($translator->translate('Access denied'));
在重定向代码之后,我确实被重定向到了网址http://[servername]/error/403
,但页面的内容是,而不是我的自定义403.phtml
,是一个样式化的(带布局)404错误页面,说明“请求的URL无法通过路由匹配。”
答案 0 :(得分:4)
实现目标的更好方法是在dispatch.error
函数中触发checkAcl
事件,而不是尝试重定向。然后,您可以处理此事件并显示403页面。
触发事件:
if (!$this->acl->isAllowed($userRole, $controller, $privilege))
{
$app = $e->getTarget();
$route = $e->getRouteMatch();
$e->setError('ACL_ACCESS_DENIED') // Pick your own value, would be better to use a const
->setParam('route', $route->getMatchedRouteName());
$app->getEventManager()->trigger('dispatch.error', $e);
}
然后在你的onBootstrap中为dispatch.error
事件添加一个监听器:
use Zend\Mvc\MvcEvent;
...
$eventManager->attach(MvcEvent::EVENT_DISPATCH_ERROR, <any callable>, -999);
在您刚刚附加到dispatch.error
事件的回调中:
$error = $event->getError();
if (empty($error) || $error != "ACL_ACCESS_DENIED") {
return;
}
$result = $event->getResult();
if ($result instanceof StdResponse) {
return;
}
$baseModel = new ViewModel();
$baseModel->setTemplate('layout/layout');
$model = new ViewModel();
$model->setTemplate('error/403');
$baseModel->addChild($model);
$baseModel->setTerminal(true);
$event->setViewModel($baseModel);
$response = $event->getResponse();
$response->setStatusCode(403);
$event->setResponse($response);
$event->setResult($baseModel);
return false;