在父控制器中重定向
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');
}
}
});
}
}
权限保存在数据库中。
在我的 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');
}
}
});
}
}
权限保存在数据库中。