【问题标题】:building a 'two-way' OO dynamic ACL system构建“双向”OO 动态 ACL 系统
【发布时间】:2011-11-16 05:10:38
【问题描述】:

这个问题是在为自定义应用程序设计专用 ACL 系统时提出的,但我认为它一般适用于 ACL 系统,因为我还没有通过查看一些主流系统找到如何解决这个问题,喜欢Zend_ACL

在我的应用程序中,权限是动态授予的,例如:用户获得对活动的查看权限,因为他是活动所链接到的团队的成员。这是基于您始终有一个 Employee(用户)想要对 Item(我的应用程序中的一个对象,例如 Activity、Team 等)执行操作(查看/编辑/等)的假设.这足以满足我的目标用途;

$Activity = new Activity( $_POST['activity_id'] );

$Acl = new Acl( $Activity );
if ( !$Acl->check( 'edit' ) {
    throw new AclException('no permission to edit');
}

我的 Acl 类包含授予权限的所有业务规则,它们是“动态”创建的(尽管有时出于性能原因缓存);

/**
 * Check the permissions on a given activity.
 * @param Activity $Activity
 * @param int $permission (optional) check for a specific permission
 * @return mixed integer containing all the permissions, or a bool when $permission is set
 */
public function checkActivity( Activity $Activity, $permission = null ) {
    $permissions = 0;

    if ( $Activity->owner_actor_id == $this->Employee->employee_id ) {
        $permissions |= $this->activity['view'];
        $permissions |= $this->activity['remove'];
        $permissions |= $this->activity['edit'];
    } elseif ( in_array( $this->Employee->employee_id, $Activity->contributor_ids_arr ) ) {
        $permissions |= $this->activity['view'];
    } else {
        /**
         * Logged in user is not the owner of the activity, he can contribute 
         * if he's in the team the activity is linked to
         */
        if ( $Activity->getTeam()->isMember( $this->Employee ) ) {
            $permissions |= $this->activity['view'];
        }
    }

    return ( $permission ? ( ( $permission & $permissions ) === $permission ) : $permissions );
}

这个系统可以正常工作。

当您想要“反转”ACL 规则时,就会出现这种方法的问题。例如,“获取我允许编辑的所有活动”。我不想在需要活动的代码中放入像WHERE owner_actor_id = $Employee->employee_id 这样的任何逻辑,因为这是Acl 类的职责,它应该保持集中。对于当前的实现,我没有其他选择来获取代码中的所有活动,然后一一声明它们。这当然是一种非常低效的方法。

所以我正在寻找关于一个好的架构的一些想法(或指向现有 ACL 实现或一些相关设计模式的指针)来创建一个 ACL 系统,该系统可以以某种方式同时执行 hasPermission( $Item, $permission )fetchAllItems( $permission ),理想情况下,使用相同的业务规则集。

提前谢谢大家!


我查看了Zend_ACL 的实现,但它更侧重于一般权限。我还在 SO 上发现了以下问题:

但不幸的是,他们似乎也没有回答这个问题。

【问题讨论】:

  • 反对将fetchAllItems() 方法放在Acl 类中的理由是什么?我不确定我是否真的理解这个问题。

标签: php oop design-patterns acl


【解决方案1】:

一位同事就此事向我提出了另一种看法,这也可能是解决这个问题的方法。

认为我想要的是将所有与访问相关的代码放在 ACL 类中(反映了我的声明 “我不想放任何像WHERE owner_actor_id = $Employee->employee_id 这样的逻辑在需要活动的代码中,因为这是 Acl 类的责任,它应该保持集中。”)。

真正想要确保用户永远无法访问不符合 ACL 类中列出的规则的内容。如果“工作代码”已经获取了数据的子集,这真的不是问题——只要它最终与“真正的”ACL 进行了检查。可能发生的最糟糕的情况是用户看到的比他应该看到的少,这比更多的要好。

使用这种“解决方案”(如果您愿意,可以选择替代方法),您可以避免获取所有数据,同时保持将所有规则集中在一个位置的好处。我能想到的任何其他解决方案都会涉及到规则的重复,因为您需要 PHP 中的规则来检查给定的资源,以及用 MySQL 编写的规则来获取所有资源。

顺便说一句,将子集获取代码放在Acl 类中仍然是可能的——但是我认为保持类小而专注会更好(因为我认为其中的代码可读性类也很重要)。

【讨论】:

  • @Xeoncross:当然,你有什么不明白的?
【解决方案2】:

您可能想查看 cakephp 解决此问题的方法:

http://book.cakephp.org/view/1543/Simple-Acl-controlled-Application

【讨论】:

  • 我觉得很难理解。但是,权限似乎仍然是每个用户/组的硬编码,对吧?我需要动态授予它们..
【解决方案3】:

据我所知,应该使用 ACL 来检查一般权限。基于实体的权限不应成为 ACL 的主题。对于这样的任务,我将看看 Linux/Unix 如何管理文件权限。

          owner    group   all
read        1        1      1
write       1        0      0
execute     1        0      0
--------------------------------------
            7        4      4

通过类似的实现,获取和检查权限都很容易,但您需要在应用程序中再添加一层。

编辑: 此外,该架构将尊重单一职责原则,因为检查“是否允许用户打开页面”不同于“用户将在页面上看到的内容”

【讨论】:

  • 但那是一个权限系统,你只能看到所有者、组和所有实体,并且该权限的一个重要部分是拥有一个所有者。这是 ACL,您将指定的用户和组分配给一些具有继承规则和组规则的操作。
  • 我看不出fileActivity object 之间的区别——它们都是“实体”,对吧?并且用户可以对实体拥有一组权限,例如“查看”、“编辑”、“删除”或“读取”、“写入”、“执行”(在 Linux 的情况下)。我的系统和 Linux 的不同之处在于,我的权限是从上下文中派生的,而不是每个实体的硬编码。
【解决方案4】:

这似乎更像是基于角色的访问控制或 RBAC,而不是访问控制列表 ACL,因为您授予用户对对象的权限取决于具有什么角色,如果他们在组中,协作列表或是所有者,但您没有存储为角色,因此不能是 RBAC,但您没有存储权限,因为您假设它不能成为 ACL。

因此,如果您想通过您假设的权限查询一组对象,显然您需要先计算分配的权限才能获取它们。

然后,如果您希望在数据库中不获取所有内容,或者创建 ACL 表/列表,或者链接到您想要授予他们权限的对象的角色权限,那么您可以在存储过程/udf 函数中计算它。

希望这是有用的,好问题让我有点头疼,但现在我需要做一些类似的事情......祝你有美好的一天

【讨论】:

  • 感谢您的评论!我研究了 RBAC,但它似乎不适合我的情况。 Wikipedia 声明“RBAC 不是动态分配授权的模型”——我相信动态分配是我在这里尝试做的。
  • 我想说的一点是关于 RBAC 是一个集中的访问控制实体,并且要获得对对象的授权,您需要向该实体请求许可。另一方面,ACL 有一个列表链接或在对象中,API 询问对象的 ACL 是否授予用户访问权限。如果您想在不从数据库中获取所有内容的情况下进行动态分配,您唯一的解决方案是 UDF 函数/存储过程,如果您对如何编写有疑问,请询问。
猜你喜欢
  • 2011-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-05
  • 1970-01-01
相关资源
最近更新 更多