Этот вопрос возник при разработке выделенной системы ACL для пользовательского приложения, но я думаю, что это относится к системам ACL в целом, так как я не узнал, как решить эту проблему, просмотрев некоторые из основных систем, например Zend_ACL
.
В моем приложении разрешения предоставляются динамически, например: пользователь получает разрешения на просмотр для деятельности, потому что он является членом команды, к которой связана деятельность. Это основывается на предположении, что у вас всегда есть Employee
(пользователь), который хочет выполнить действие (просмотр/редактирование/etc) на 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 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:
Но, к сожалению, они, похоже, тоже не отвечают на вопрос.