构建“双向”OO动态ACL系统

时间:2011-09-13 13:57:47

标签: php oop design-patterns acl

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

在我的应用程序中,动态授予权限,例如:用户获取活动的查看权限,因为他是活动链接到的团队的成员。这建立在假设您总是有一个Employee(用户)想要在Item上执行操作(查看/编辑/等)的假设(我的应用程序中的一个对象,例如Activity,团队等)。这足以让我有针对性地使用;

$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实现或某些相关设计模式的指针)的一些想法,以创建一个可以某种方式同时执行hasPermission( $Item, $permission )和{{{ 1}},理想情况下使用相同的业务规则集。

提前谢谢大家!


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

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

4 个答案:

答案 0 :(得分:1)

一位同事向我提出了另一个关于此问题的观点,这也可能是解决这个问题的方法。

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

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

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

顺便说一下,将子集获取代码放在Acl类中仍然是可能的 - 但我认为保持类较小且集中(因为我认为代码的可读性)会更好那个班级也很重要。)

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

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

使用类似的实现,提取和检查权限都很简单,但您需要在应用程序中再添加一层。

编辑: 此架构还将尊重单一责任原则,只要检查“是否允许用户打开页面”与“用户将在页面上看到什么”不同

答案 3 :(得分:0)

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

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

然后你可以在存储过程/ udf函数中计算它,如果你想在db中不获取all,或者创建一个ACL表/列表,或者链接到你想给它们权限的对象的Role权限。 / p>

希望这是有用的,好问题它有点炒我的大脑,但现在我需要做类似的事情......祝你有个美好的一天