Rij*_*ijk 16 php oop acl design-patterns
在为自定义应用程序设计专用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');
}
Run Code Online (Sandbox Code Playgroud)
我的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 );
}
Run Code Online (Sandbox Code Playgroud)
这个系统工作正常.
当您想要"反转"ACL规则时,会出现此方法的问题.例如,"获取我允许编辑的所有活动".我不想WHERE owner_actor_id = $Employee->employee_id在需要活动的代码中加入任何逻辑,因为这是Acl类的责任,应该保持集中.在当前的实现中,我没有其他选择来获取代码中的所有活动,然后逐个断言它们.这当然是一种非常低效的方法.
所以我正在寻找的是关于良好架构(或指向现有ACL实现或某些相关设计模式的指针)的一些想法,以创建一个可以某种方式同时执行这两者的ACL系统,hasPermission( $Item, $permission )并且fetchAllItems( $permission )理想情况下使用相同的业务规则集.
谢谢大家!
我已经查看了Zend_ACL实现,但更侧重于一般权限.我还在SO上找到了以下问题:
但不幸的是,他们似乎也没有回答这个问题.
一位同事向我提供了对此事的另一种看法,这也可能是解决这个问题的方法。
我认为我想要的是将所有与访问相关的代码放入 ACL 类中(反映了我的声明:“我不想WHERE owner_actor_id = $Employee->employee_id在需要活动的代码中放入任何逻辑,因为这是 Acl 类的责任,并且它应该保持集中。”)。
我真正想要的是确保用户永远无法访问不符合 ACL 类中列出的规则的内容。这不是真的问题——只要它最终根据“真实”ACL 进行检查。可能发生的最糟糕的情况是用户看到的内容比他预期看到的要少,但这比看到的更多要好得多。
使用这个“解决方案”(如果愿意的话,可以使用替代方法),您可以避免获取所有数据,同时保持将所有规则集中在一个位置的好处。我能想到的任何其他解决方案都将涉及规则的重复,因为您需要 PHP 中的规则来检查给定资源,并需要用 MySQL 编写的规则来获取所有资源。
顺便说一句,仍然可以将子集获取代码放在类中Acl- 但是我认为最好保持类较小且集中(因为我认为该类中代码的可读性也非常重要) 。