重构每个Zf2控制器操作的一些调用

时间:2015-06-11 07:54:36

标签: php architecture zend-framework2 refactoring

我需要执行自定义isGranted方法(不使用社区中的Rbac或acl模块)。所以我有一个提供功能的服务。但是这段代码:

if (!$this->userService->isGrantedCustom($this->session->offsetGet('cod_lvl'), 'ZF_INV_HOM')) {
    throw new \Exception("you_are_not_allowed", 1);
}

...在每个控制器和每个动作中重复。参数正在变化当然取决于权限('ZF_INV_HOM''ZF_TODO_DELETE' ...)。

我认为在调用控制器之前执行此代码并不是一个坏主意,但我无法确定什么是最佳解决方案(最佳架构),以及如何将这些参数传递给它(我考虑过控制器上的注释但是如何处理它?)。

关键是,如果我必须修改此代码,我无法想象这样做数百次,对于每个控制器,我需要执行的每个操作都需要将此代码放在一个位置。

1 个答案:

答案 0 :(得分:2)

通过将事件侦听器附加到SharedEventManager,您可以定位所有控制器并在一个位置进行授权检查。

在这种情况下,目标是Zend\Mvc\Controller\AbstractActionController,这意味着任何扩展它的控制器都将执行监听器。此侦听器的高优先级意味着它在目标控制器操作之前执行,使您有机会处理任何未经授权的请求。

public function onBootstrap(MvcEvent $event)
{
    $application  = $event->getApplication();
    $eventManager = $application->getEventManager()->getSharedManager();

    $eventManager->attach(
        \Zend\Mvc\Controller\AbstractActionController::class, // Identity of the target controller
        MvcEvent::EVENT_DISPATCH,
        [$this, 'isAllowed'],
        1000  // high priority
    );
}

在每个控制器中,您需要通过某种方式确定哪种资源'正在访问。

作为一个例子,它可以实现这个接口

interface ResourceInterface
{
    // Return a unique key representing the resource
    public function getResourceId();
}

听众可能看起来像这样。

public function isAllowed(MvcEvent $event)
{
    $serviceManager = $event->getApplication()->getServiceManager();

    // We need the 'current' user identity
    $authService = $serviceManager->get('Zend\Authentication\AuthenticationService');
    $identity = $authService->getIdentity();

    // The service that performs the authorization
    $userService = $serviceManager->get('MyModule\Service\UserService');

    // The target controller is itself a resource (the thing we want to access)
    // in this example it returns an resource id so we know what we want to access
    // but you could also get this 'id' from the request or config etc
    $controller = $event->getTarget();

    if ($controller instanceof ResourceInterface) {
        $resourceName = $controller->getResourceId();

        // Test the authorization, is UserX allowed resource ID Y
        if (empty($resourceName) || $userService->isGrantedCustom($identity, $resourceName)) {
            // early exit for success
            return;
        } else {
           // Denied; perhaps trigger a new custom event or return a response
        }
    }

}