我需要执行自定义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'
...)。
我认为在调用控制器之前执行此代码并不是一个坏主意,但我无法确定什么是最佳解决方案(最佳架构),以及如何将这些参数传递给它(我考虑过控制器上的注释但是如何处理它?)。
关键是,如果我必须修改此代码,我无法想象这样做数百次,对于每个控制器,我需要执行的每个操作都需要将此代码放在一个位置。
答案 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
}
}
}