Zend ACL 是否适合我的需求?

2021-12-29 00:00:00 php zend-framework zend-acl zend-auth

我的应用程序基于 Zend 框架.我正在使用 Zend_Auth 进行身份验证,但我不确定 Zend_Acl 是否适合我,因为坦率地说,我所看到的示例对于我的需求来说太简单了或者让我困惑.

I have based my application upon the Zend Framework. I am using Zend_Auth for authentication, but I'm not sure if Zend_Acl will work for me because, frankly, the examples I've seen are either too simplistic for my needs or confuse me.

我将应用程序中的元素视为资源,并且这些资源可以拥有特权.包含资源特权的角色是动态定义的,分配给用户.我将此信息存储在规范化表中.

I'm thinking of elements in my application as Resources and these Resources can have have Privileges. Roles containing Resource Privileges are dynamically defined assigned to users. I'm storing this information in normalized tables.

  1. 用户有角色
  2. 一个角色可以有多个资源
  3. 资源可以有多个权限

角色实际上只是没有层次结构的资源权限的集合.资源的一个例子是页面".每个人都可以查看页面,但经过身份验证的用户需要添加"、编辑"或删除"权限才能对页面执行任何其他操作.

Roles are really just collections of Resource Privileges with no hierarchy. An example of a Resource would be 'Page'. Everyone can view the pages, but a authenticated user would need 'add', 'edit', or 'delete' privileges to do anything else with pages.

这是否与 Zend ACL 匹配?我是否会以一种会给我带来问题的方式考虑 ACL?

Does this mesh with Zend ACL? Am I thinking ACL in a way that's going to create problems for me?

我的解决方案

Typeonerror 值得称赞,但这是我的具体解决方案.

Typeonerror gets the credit, but here's my specific solution.

我扩展了 Zend_Acl 以简化我的使用,因为我只加载当前用户的角色:

I extended Zend_Acl to simplify my usage because I only load the role of the current user:

class My_Acl extends Zend_Acl
{
    protected $_role_id;

    public function setRole($role_id)
    {
        $this->_role_id = $role_id;
        return $this->addRole($role_id);
    }

    public function getRole()
    {
        return $this->_role_id;
    }

    public function deny($resource, $privilege)
    {
        return parent::deny($this->_role_id, $resource, $privilege);
    }

    public function allow($resource, $privilege)
    {
        return parent::allow($this->_role_id, $resource, $privilege);
    }

    public function isAllowed($resource, $privilege)
    {
        return parent::isAllowed($this->_role_id, $resource, $privilege);
    }
}

为了填充 ACL,我执行了一个返回 resourceprivilegerole_id 列的查询.如果用户的角色没有该权限,则结果集中的 role_id 列为空.

To populate the the ACL I execute a query which returns resource, privilege, and role_id columns. The role_id column is null in the result set if the user's role does not have that privilege.

$acl = new My_Acl();

$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
    $userInfo = $auth->getStorage()->read();
    $acl->setRole($userInfo->role_id);
} else {
    $acl->setRole('');
}

// QUERY HERE

foreach ($privileges as $privilege) {
    if (!$acl->has($privilege['resource'])) {
        $acl->addResource($privilege['resource']);
    }
    if (is_null($privilege['role_id'])) {
        $acl->deny($privilege['resource'], $privilege['privilege']);
    } else {
        $acl->allow($privilege['resource'], $privilege['privilege']);
    }
}

推荐答案

这正是它的工作原理,我认为您正在以一种准确的方式考虑它.您可以添加资源,然后添加权限以允许某些用户角色访问它们.例如,在我的 CMS 中,我有开发人员"、管理员"和用户".在下面的代码中,我添加了一般访问权限,然后从某些用户的访问权限中删除了一些操作和特定方法.当然,这非常特定于我的应用程序,但基本上,您必须从 auth->getIdentity()(或类似的)获取用户的角色,然后从数据库中添加您的角色/资源.

That's exactly how it works and I think you're thinking about it in an accurate way. You can add your resources and then add privileges to allow certain user roles to access them. For example, in my CMS, I have "developers", "admins", and "users". In the code below I add general access and then remove some actions and specific methods from certain user's access. Of course this is pretty specific to my application but basically, you'd have to get the user's role from auth->getIdentity() (or similar) and then add your roles/resources from the database.

<?php

/**
 * @author     Benjamin Borowski <ben.borowski@typeoneerror.com>
 * @copyright  Copyright (c) Typeoneerror Studios http://typeoneerror.com
 * @version    $Id$
 * @category   Typeoneerror
 * @package    Acl
 */

/**
 * Defines basic roles and resources for an application as
 * well as a Content Management System (CMS).
 *
 * Zend_Acl provides a lightweight and flexible access control list
 * (ACL) implementation for privileges management.
 *
 * {@inheritdoc}
 *
 * @author     Benjamin Borowski <ben.borowski@typeoneerror.com>
 * @copyright  Copyright (c) Typeoneerror Studios http://typeoneerror.com
 * @version    $Id$
 * @category   Typeoneerror
 * @package    Acl
 */
class Typeoneerror_Acl extends Zend_Acl
{
    /**
     * Constructor function.
     *
     * Creates basic roles and resources and adds them to Acl.
     *
     * {@inheritdoc}
     *
     * @return Typeoneerror_Acl
     */
    public function __construct()
    {
        //---------------------------------------
        // ROLES
        //---------------------------------------

        $this->_addRole("guest")
             ->_addRole("member", "guest")
             ->_addRole("admin", "member")
             ->_addRole("developer", "admin");

        //---------------------------------------
        // FRONT-END RESOURCES
        //---------------------------------------

        $this->_add("default");

        //---------------------------------------
        // BACK-END RESOURCES
        //---------------------------------------

        $this->_add("cms")
             ->_add("cms:articles", "cms")
             ->_add("cms:auth", "cms")
             ->_add("cms:bug-report", "cms")
             ->_add("cms:calendar", "cms")
             ->_add("cms:categories", "cms")
             ->_add("cms:comments", "cms")
             ->_add("cms:error", "cms")
             ->_add("cms:galleries", "cms")
             ->_add("cms:pages", "cms")
             ->_add("cms:photos", "cms")
             ->_add("cms:tags", "cms")
             ->_add("cms:users", "cms");

        //---------------------------------------
        // GUEST PERMISSIONS
        //---------------------------------------

        $this->allow("guest", "default")
             ->allow("guest", "cms:auth")           // -- guests can attempt to log-in
             ->allow("guest", "cms:error")          // -- guests can break stuff
             ->allow("guest", "cms:bug-report");    // -- guests can report bugs

        //---------------------------------------
        // ADMIN PERMISSIONS
        //---------------------------------------

        $this->allow("admin")
             ->deny("admin", null, "purge")                       // -- admins cannot purge (normally)
             ->deny("admin", "cms:comments", "create");           // -- only devs can create a comment

        //---------------------------------------
        // DEVELOPER PERMISSIONS
        //---------------------------------------

        $this->allow("developer");             // -- unrestricted access

        return $this;
    }

    /**
     * Adds a Resource having an identifier unique to the ACL.
     *
     * @param Zend_Acl_Resource_Interface $resource       The resource to add
     * @param Zend_Acl_Resource_Interface|string $parent  A parent resource it inherits from
     * @return Typeoneerror_Acl                           Reference to Acl class
     */
    protected function _add($resource, $parent = null)
    {
        $this->add(new Zend_Acl_Resource($resource), $parent);

        return $this;
    }

    /**
     * Wrapper for <code>addRole</code>
     *
     * @param Zend_Acl_Resource_Interface $resource        The resource to add
     * @param Zend_Acl_Resource_Interface|string $parents  Parent resources it inherits from
     * @return Typeoneerror_Acl                            Reference to Acl class
     */
    protected function _addRole($role, $parents = null)
    {
        $this->addRole(new Zend_Acl_Role($role, $parents));

        return $this;
    }

}

编辑

我想我还应该解释一下,我有一个 Typeoneerror_Controller_Plugin_Acl,每当请求任何资源时都会使用它.在这里,我创建了请求资源制作的标签"并检查用户是否有权访问该标签:

Guess I should also explain that I have an Typeoneerror_Controller_Plugin_Acl which is used whenever any resource is requested. Here I create the "tag" that the requested resource makes and check whether the user has access to that tag:

    $controller = $request->controller;
    $action = $request->action;
    $module = (empty($request->module)) ? "default" : $request->module;

    // -- this ends up like "cms:articles" just like my resources
    $resource = $module . ":" . $controller;

    if (!$this->__acl->has($resource))
    {
        $resource = $module;
    }

    // -- the good stuff. check if the user's role can access the resource and action
    if (!$this->__acl->isAllowed($role, $resource, $action))
    {
        //more code 
    }

相关文章