jkardynia/acl-annot

Zend Framework 2 的 ACL 注解

0.0.1 2014-04-05 17:41 UTC

This package is not auto-updated.

Last update: 2024-09-24 06:21:32 UTC


README

Build Status Scrutinizer Code Quality Code Coverage

使用 Zend Framework 2 的 ACL 注解,此包允许您通过注解在 Zend 控制器中编写 ACL 规则。

安装

您可以通过 composer 安装它。只需将以下内容添加到 composer.json 中的依赖项

"jkardynia/acl-annot": "*"

使用方法

使用 ACL 注解非常简单。您需要做的就是使用 @Acl 注解来定义您在定义控制器的地方的用户角色的访问规则。

在控制器中添加规则

以下示例将向您展示如何使用 ACL 注解与 AlbumController(来自 Zend Framework 2 教程的示例)一起使用 - 入门 - 创建控制器

<?php
namespace Album\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use \jkardynia\Annotations\Permissions\Acl\Acl;

class AlbumController extends AbstractActionController
{

    /**
     * @Acl("Allow", roles="admin, guest") 
     */
    public function indexAction()
    {
    }

    /**
     * @Acl("Allow", roles="admin") 
     */
    public function addAction()
    {
    }

    /**
     * @Acl("Allow", roles="admin") 
     */
    public function editAction()
    {
    }

    /**
     * @Acl("Allow", roles="admin") 
     */
    public function deleteAction()
    {
    }
}

更改不多。我仅通过 use 关键字导入了 ACL 注解类,并使用了这些注解。如您所见,我只允许访客访问 indexAction,并允许管理员访问所有操作。

这是定义 ACL 规则,但在这些规则开始工作之前,您的模块必须收集所有规则。

构建访问控制列表

ACL 应在应用初始化之初就填充。考虑到这一点,您应该通过将新的闭包附加到 MvcEvent 来准备您的模块。您可以这样操作

<?php
namespace Album;

use Zend\Mvc\MvcEvent;
use \jkardynia\Zend\Permissions\Acl\AclItemsCollector;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\ModuleManager\Feature\ConfigProviderInterface;

class Module implements  AutoloaderProviderInterface, ConfigProviderInterface
{
    /**
     * @var \Zend\Permissions\Acl\Acl 
     */
    private $acl = null;

    public function init(\Zend\ModuleManager\ModuleManager $m){
        $event = $m->getEventManager()->getSharedManager();
        
        $event->attach('Zend\Mvc\Application', MvcEvent::EVENT_BOOTSTRAP, function (MvcEvent $e){
            $collector = new AclItemsCollector();
        
            $collector->getAcl()->addRole('guest');
            $collector->getAcl()->addRole('admin', 'guest');
            $collector->addEntriesFromResourceClass('Album\Controller\AlbumController');
            $this->acl = $collector->getAcl();
        });
    }

    // other stuff
}

现在我们有了一个访问控制列表,我们可以使用它来检查当前用户的访问权限。注意,我添加了一个私有字段 \Zend\Permissions\Acl\Acl $acl,它是在 ACL 初始化回调中初始化的。我们稍后会用到它。

检查访问

检查用户是否有权访问我们的控制器是 ACL 系统的主要目的。我们应该在 ActionController dispatch 中检查访问权限。为此,首先我们必须在模块中添加一个新的事件订阅者(回调)。

class Module implements  AutoloaderProviderInterface, ConfigProviderInterface
{
    //some initialization

    public function onBootstrap(MvcEvent $e){
        $eventManager = $e->getApplication()->getEventManager();
        
        $eventManager->attach(MvcEvent::EVENT_ROUTE, function(MvcEvent $e){
        
            $application = $e->getApplication();
            $sm = $application->getServiceManager();
            $sharedManager = $application->getEventManager()->getSharedManager();
            $router = $sm->get('router');
            $request = $sm->get('request');
            $matchedRoute = $router->match($request);

            if (null !== $matchedRoute) {
                $acl = $this->acl;
                
                $sharedManager->attach('Zend\Mvc\Controller\AbstractActionController', MvcEvent::EVENT_DISPATCH, function($event) use ($sm, $acl) {
                    $userRole =  new \Zend\Permissions\Acl\Role\GenericRole('guest');

                    try{
                        $sm->get('ControllerPluginManager')->get('Acl', $acl)->checkAccess($event, $userRole);
                    }catch(AccessDeniedException $e){

                        $event->getTarget()->plugin('redirect')->toUrl('access-denied');
                        return false;
                    }
                });
            }
        });
    }

    //other stuff
}

那里发生了什么?我们只是在适当的回调中附加了回调。最重要的事情是

$userRole =  new \Zend\Permissions\Acl\Role\GenericRole('guest'); // you can get it from session

try{
    $sm->get('ControllerPluginManager')->get('Acl', $acl)->checkAccess($event, $userRole);
}catch(AccessDeniedException $e){

    $event->getTarget()->plugin('redirect')->toUrl('access-denied');
    return false;
}

在那里,我们从 ControllerPluginManager 获取 Acl 插件,并使用它来检查访问权限。如果访问被拒绝,将会抛出异常,所以我捕获它并将重定向到访问被拒绝的信息页面。

还有最后一件事要做。我们必须注册 Acl 插件。

注册 ACL 插件

为了在您的模块中注册任何新的插件,您只需在 module.config.php 文件中添加一行即可

'controller_plugins' => array(
    'invokables' => array(
        'Acl' => '\jkardynia\Zend\Controller\Plugin\Acl',
    )
)

现在一切就绪 - 您可以使用注解来提供和检查对您控制器的访问 :)

性能

说实话,注解很慢,如果您想在真实应用中使用它们,您应该启用缓存。幸运的是,这个项目使用了 Doctrine Annotations 提供的很好的缓存系统。您可以使用提供的缓存策略之一,例如:APC、Memcache、Files 等。您可以直接从您的模块中配置缓存。您需要做的就是使用支持缓存的 Reader 初始化 AclItemsCollector。以下是一个文件系统缓存的示例

<?php
namespace Album;

use Zend\Mvc\MvcEvent;
use \jkardynia\Zend\Permissions\Acl\AclItemsCollector;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use \Zend\Permissions\Acl\Acl;
use \jkardynia\Annotations\Permissions\Acl\Parser\AclParser;
use \Doctrine\Common\Annotations\AnnotationReader;
use \Doctrine\Common\Annotations\CachedReader;
use \Doctrine\Common\Cache\FilesystemCache;

class Module implements  AutoloaderProviderInterface, ConfigProviderInterface
{
    /**
     * @var \Zend\Permissions\Acl\Acl 
     */
    private $acl = null;

    public function init(\Zend\ModuleManager\ModuleManager $m){
        $event = $m->getEventManager()->getSharedManager();
        
        $event->attach('Zend\Mvc\Application', MvcEvent::EVENT_BOOTSTRAP, function (MvcEvent $e){
            $parser = new AclParser(new CachedReader(
                new AnnotationReader(),
                new FilesystemCache("/path/to/cache"),
                $debug = true
            ));

            $collector = new AclItemsCollector(new Acl(), $parser);
        
            $collector->getAcl()->addRole('guest');
            $collector->getAcl()->addRole('admin', 'guest');
            $collector->addEntriesFromResourceClass('Album\Controller\AlbumController');
            $this->acl = $collector->getAcl();
        });
    }

    // other stuff
}

您可以在优秀的 [Doctrine Annotations 文档] 中找到有关注解缓存的更多信息(http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/annotations.html#setup-and-configuration)。

最后思考

这是 ACL 注解包的非常基本的实现,还有很多事情要做,但它在开发环境中可以使用。请随时参与。 :)

待办事项

还有很多事情要做。最重要的有以下几点

  • 一个动作使用多个acl注解
  • 更灵活的资源类添加
  • 定义权限