在父控制器中重定向

时间:2017-06-22 15:12:20

标签: php zend-framework2 acl

在我的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返回的内容,我只是强制重定向。

提前感谢您的回复。

3 个答案:

答案 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;
    }
}

该异常将阻止进一步执行代码,重定向将阻止呈现异常错误页面。