在我的ZF2(2.4.5)项目中,我有主(父)控制器,其功能是验证用户权限,因此每个继承的控制器都可以轻松访问它。但是重定向存在问题。我知道继承控制器的动作必须返回响应,但是可以在父控制器中强制重定向吗?
父控制器
<?php
namespace Application;
use Zend\Mvc\Controller\AbstractActionController;
class CoreController extends AbstractActionController{
public function checkAccess($moduleName, $accessName){
if($this->getAclService()->isAllowed($moduleName, $accessName)){
self::redirect()->toRoute('access-denied');
}
}
}
继承控制器
namespace Application\Controller;
use Application\CoreController;
use Zend\View\Model\ViewModel;
class InterfaceController extends CoreController{
public function indexAction(){
$this->checkAccess('Foo', 'Bar');
return new ViewModel([
]);
}
}
TL; DR如果我在$this->checkAccess('Foo', 'Bar');
中拨打InterfaceController
并在$this->getAclService()->isAllowed($moduleName, $accessName)
中CoreController
再次发送false
我想将用户重定向到路由'access-denied'
立即没有完成InterfaceController::indexAction
重要提示:我想避免检查checkAccess
返回的内容,我只是强制重定向。
提前感谢您的回复。
答案 0 :(得分:1)
好的,我是使用全局异常处理程序
完成的儿童控制器
<?php
namespace Warehouse\Controller;
use Application\CoreController;
use Zend\View\Model\ViewModel;
class IndexController extends CoreController {
public function getWarehouseDocumentAction() {
parent::checkAccess('Warehouse', 'incoming-goods');
return new ViewModel([
'foo' => 'bar',
]);
}
}
父控制器
namespace Application;
use Application\Exception\InsufficientPermissionException;
use Zend\Mvc\Controller\AbstractActionController;
class CoreController extends AbstractActionController {
public function checkAccess($moduleName, $accessName){
if(!$this->getServiceLocator()->get(MyAcl::class)->isAllowed($moduleName, $accessName, $this->identity())){
throw new InsufficientPermissionException('Access denied. Insufficient permission.');
}
}
}
Module.php
<?php
namespace Application;
use Application\Exception\InsufficientPermissionException;
use Application\Monolog\Handler\DoctrineLogMessageHandler;
use Zend\Mvc\MvcEvent;
class Module {
public function onBootstrap(MvcEvent $e) {
$sharedEvents = $e->getApplication()->getEventManager()->getSharedManager();
$sharedEvents->attach('Zend\Mvc\Application', 'dispatch.error', function (MvcEvent $event) {
if (php_sapi_name() !== 'cli') {
$exception = $event->getParam('exception');
if ($exception instanceof InsufficientPermissionException) {
$target = $event->getTarget();
return $target->redirect()->toRoute('access-denied');
}
}
});
}
}
权限保存在数据库中。
答案 1 :(得分:0)
我说这是不可能的。调用代码InterfaceController :: indexAction至少需要返回,这将启动重定向过程。
您可以通过让基本控制器设置重定向来清理它,但是继承的控制器需要通过调用 return 来停止脚本执行。
基础控制器
use Zend\Mvc\Controller\AbstractActionController;
class CoreController extends AbstractActionController{
public function checkAccess($moduleName, $accessName){
if (!$this->getAclService()->isAllowed($moduleName, $accessName))) {
self::redirect()->toRoute('access-denied');
return false;
} else {
return true;
}
}
}
继承控制器
use Application\CoreController;
use Zend\View\Model\ViewModel;
class InterfaceController extends CoreController{
public function indexAction(){
if (!$this->checkAccess('Foo', 'Bar')) {
return;
}
return new ViewModel([
]);
}
}
修改强>
作为旁注,在我们公司中,我们在基本控制器的init()方法中进行ACL检查,但不会被覆盖,因此可以在任何操作代码之前立即进行重定向运行。
编辑#2
我完全忘记了我们使用的init方法。如果您正在寻找其他解决方案,请试一试。
基础控制器
use Zend\Mvc\Controller\AbstractActionController;
class CoreController extends AbstractActionController{
public function init() {
// bootstrap code...
// This should redirect
if (!$this->_isUserAuthorized()) {
return;
}
// If the ACL check was OK then pass control to controllers
return parent::init();
}
private function _isUserAuthorized() {
// checks done here
// return true if OK
// else
$this->_response->setRedirect($this->view->defaultUrl($redirect))->sendResponse();
return false;
}
}
继承控制器
use Application\CoreController;
use Zend\View\Model\ViewModel;
class InterfaceController extends CoreController{
public function indexAction(){
// nothing to do here
return new ViewModel([]);
}
}
答案 2 :(得分:0)
你正在做一个简单的302 http重定向到&#34;访问被拒绝&#34;,所以你可以只渲染响应对象到目前为止并停止执行php:
public function checkAccess($moduleName, $accessName){
if (!$this->getAclService()->isAllowed($moduleName, $accessName))) {
self::redirect()->toRoute('access-denied');
$this->getResponse()->send();
exit;
} else {
return true;
}
}
或您可以简单地抛出异常:
public function checkAccess($moduleName, $accessName){
if (!$this->getAclService()->isAllowed($moduleName, $accessName))) {
self::redirect()->toRoute('access-denied');
throw new \Exception('access denied');
} else {
return true;
}
}
该异常将阻止进一步执行代码,重定向将阻止呈现异常错误页面。