ZF2 - 检查每个操作中获取参数的权限

ZF2 - Checking permissions for get parameter in each action

我有一个名为 "TestController" 的控制器,里面有几个动作。对于每个操作,我都会收到一个获取参数 ("id")。 类似于:

test/action1/1
test/action1/2
test/action2/1
test/action3/1
...

由于这个参数很容易修改,所以我想检查一下这个id的权限。我是否必须在每个动作中都包含此检查方法,还是有其他方法?我知道我无法在构造函数中接收参数,但这样的方式会很好。

我目前的解决方案是在插件中有一个检查方法,并在每个动作中调用它,如下所示:

if(!$this->access()->checkAccess(..., $this->params()->fromRoute('id')) {
 //redirect...
}

您可以使用 ACL(或 RBAC)进行这些检查。

使用 ACL,您可以(必须)声明应用程序的资源、使用该应用程序的角色以及角色访问资源的方式。

您可以首先将侦听器附加到控制器,在应用程序的 Module.php

class Module {
    public function onBootstrap(\Zend\Mvc\MvcEvent $event) {
        $application = $e->getApplication();
        $serviceManager = $application->getServiceManager();
        $sharedManager = $application->getEventManager()->getSharedManager();

        $router = $serviceManager->get('router');
        $request = $serviceManager->get('request');

        $matchedRoute = $router->match($request);
        if (null !== $matchedRoute) {
            $sharedManager->attach(\Zend\Mvc\Controller\AbstractActionController::class, \Zend\Mvc\MvcEvent::EVENT_DISPATCH, function($event) use ($serviceManager) {
                $serviceManager->get('ControllerPluginManager')->get('Application\Controller\Plugin\Acl')->doAuthorization($event);
            }, 2
            );
        }
    }
}

如您所见,我们将插件 Application\Controller\Plugin\Acl 附加到每个 Zend\Mvc\Controller\AbstractActionControllerdispatch 事件。

然后你必须实施你的 ACLS。

这是一个简单的例子。 默认情况下,我更愿意拒绝访问所有资源,然后逐一允许访问它们。您也可以允许访问所有内容,然后拒绝访问单个资源,但这种方式您必须更加小心。如果您全部拒绝并忘记了某些内容,用户将无法访问它应该访问的内容。如果您允许所有内容而忘记了某些内容,则用户可能会看到他们不应该看到的内容。安全总比后悔好 ;)

namespace Application\Controller\Plugin;

class Acl extends \Zend\Mvc\Controller\Plugin\AbstractPlugin implements \Zend\ServiceManager\ServiceLocatorAwareInterface {

    private $serviceLocator;

    public function doAuthorization(\Zend\Mvc\MvcEvent $event) {
        // Retrieve user role, if you have them or just use guest
        $role = 'guest';

        $resource = get_class($event->getTarget());
        $action = $event->getRouteMatch()->getParams()['action'];

        if (!$this->getAcl()->isAllowed($role, $resource, $action)) {
            // Handle the access denied
            // Could be a redirect to login/home page, or just an 404 page
        }

    }

    public function getAcl() {
        // Create the ACL object
        $acl = new \Zend\Permissions\Acl\Acl();

        // Add your roles
        $acl->addRole(new \Zend\Permissions\Acl\Role\GenericRole('guest'));

        // Add your resources
        $acl->addResource(new Resource(\YourModule\Controller\YourController::class));

        // By default, block access to all resources.
        $acl->deny();

        // Add, one by one, access to resources for all roles
        $acl->allow('guest', \YourModule\Controller\YourController::class, ['action1', 'action2'], new \YourModule\Assertion\YourIdAssertion());

        return $acl;

    }

    public function getServiceLocator() {
        return $this->serviceLocator;
    }

    public function setServiceLocator(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator) {
        $this->serviceLocator = $serviceLocator;
    }

}

方法 allow 允许您定义这些参数:

  • 角色(强制)
  • 资源(必填)
  • 操作(可选)
  • 断言class(可选)

最后,声明了哪些角色可以访问特定资源的特定动作后,也可以告诉ACL一个"rule",如"access the action only if it this condition is met"。这些规则通过 Assertions:

指定
use Zend\Permissions\Acl\Assertion\AssertionInterface;
use Zend\Permissions\Acl\Acl;
use Zend\Permissions\Acl\Role\RoleInterface as Role;
use Zend\Permissions\Acl\Resource\ResourceInterface as Resource;

class YourAssertion implements AssertionInterface {

    public function __construct($serviceManager) {
        // construct

    }

    public function assert(Acl $acl, Role $role = null, Resource $resource = null, $privilege = null) {
        $isAllowed = false;

        // Your logic to check if an user can access a specific id or not
        //  if(...){
        //      $isAllowed = true;
        //  }

        return $isAllowed;

    }

}

希望对您有所帮助!