在父控制器中重定向

Redirect in parent controller

在我的 ZF2 (2.4.5) 项目中,我的主(父)控制器具有验证用户权限的功能,因此每个继承的控制器都可以轻松访问它。但是重定向有问题。我知道继承控制器的操作必须 return 响应,但是否可以在父控制器中强制重定向?

父控制器

<?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 如果我在 InterfaceController 中调用 $this->checkAccess('Foo', 'Bar'); 并在 CoreController 中调用 $this->getAclService()->isAllowed($moduleName, $accessName) returns false 我想重定向用户立即路由 'access-denied' 而无需完成 InterfaceController::indexAction

的其余部分

重要提示:我想避免检查 checkAccess return 的内容,我只是强制重定向。

提前感谢您的回复。

我敢说这是不可能的。调用代码 InterfaceController::indexAction 至少需要 return 才能启动重定向过程。

您可以通过让基本控制器设置重定向来稍微清理一下,但是继承的控制器需要通过调用 return.[= 来停止脚本执行14=]

基地控制器

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([]);
    }
}

您正在做一个简单的 302 http 重定向到 "access-denied",因此您可以只呈现到目前为止的响应对象并停止 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;
    }
}

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

好的,我使用全局异常处理程序做到了这一点

子控制器

<?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');
                }
            }
        });

    }
}

权限保存在数据库中。