Esta pregunta surgió al diseñar un sistema de ACL dedicado para una aplicación personalizada, pero creo que se aplica a los sistemas de ACL en general, ya que no he descubierto cómo abordar este problema mirando algunos de los sistemas principales, como Zend_ACL
.construyendo un sistema de ACL dinámico OO 'bidireccional'
En mi aplicación, los permisos se otorgan dinámicamente, por ejemplo: un usuario obtiene permisos de vista en una actividad porque es un miembro del equipo al que está vinculada la actividad. Esto se basa en la suposición de que siempre tiene un Employee
(usuario) que quiere realizar una acción (ver/editar/etc) en un Item
(uno de los objetos en mi aplicación, por ejemplo, Actividad, Equipo, etc.). Esto es suficiente para mi uso específico;
$Activity = new Activity($_POST['activity_id']);
$Acl = new Acl($Activity);
if (!$Acl->check('edit') {
throw new AclException('no permission to edit');
}
Mi clase Acl
contiene todas las reglas de negocio para conceder los permisos, y son creados 'sobre la marcha' (aunque a veces en caché por motivos de rendimiento);
/**
* 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);
}
Este sistema funciona bien tal como está.
El problema con este enfoque surge cuando quiere 'revertir' las reglas de la ACL. Por ejemplo, "buscar todas las actividades que tengo permiso para editar". No quiero poner ninguna lógica como WHERE owner_actor_id = $Employee->employee_id
en el código que necesita las actividades, porque esta es la responsabilidad de la clase Acl
y debe mantenerse centralizada. Con la implementación actual, no tengo otra opción que recuperar todas las actividades en el código y luego afirmarlas una a una. Este es, por supuesto, un enfoque muy ineficiente.
Lo que estoy buscando es algunas ideas sobre una buena arquitectura (o un puntero a una implementación de ACL existente o algunos patrones de diseño pertinentes) para crear un sistema de ACL que de alguna manera puede hacer ambas cosas hasPermission($Item, $permission)
fetchAllItems($permission)
y, a ser posible con el el mismo conjunto de reglas comerciales.
¡Gracias a todos por adelantado!
He mirado en la implementación Zend_ACL
, sino que se centra más en los permisos generales. También encontré las siguientes preguntas aquí en SO:
Pero, lamentablemente, no parecen responder a la pregunta tampoco.
¿Cuál es el argumento en contra de poner los 'fetchAllItems()' en el método 'Clase Acl'? No estoy seguro de entender realmente la pregunta. – erisco