Tabla de contenidos
Zend_Acl proporciona una implementación ligera y flexible de listas de control
de acceso (ACL) para la gestión de privilegios. En general, una
aplicación puede utilizar dichas ACL para controlar el acceso a determinados
objetos protegidos por parte de otros objetos solicitantes.
Para efectos de esta documentación:
un recurso es un objeto al que se controla el acceso.
un rol es un objeto que puede solicitar acceso a un recurso.
Dicho de manera sencilla, los roles solicitan acceso a los recursos. Por ejemplo, si un encargado de estacionamiento solicita acceso a un automóvil, entonces el encargado de estacionamiento es el rol solicitante, y el automóvil es el recurso, ya que no a todos se les puede conceder acceso al automóvil.
Mediante la especificación y el uso de una ACL, una aplicación puede controlar cómo se conceden a los roles el acceso a los recursos.
Crear un recurso en Zend_Acl es muy sencillo.
Zend_Acl proporciona el recurso
Zend_Acl_Resource_Interface para facilitar la creación de recursos en
una aplicación. Una clase solo necesita implementar esta interfaz, que consta de un único
método, getResourceId(), para que Zend_Acl
reconozca al objeto como un recurso. Adicionalmente,
Zend_Acl_Resource es proporcionado por Zend_Acl
como una implementación básica de recurso para que los desarrolladores la extiendan según lo
necesiten.
Zend_Acl proporciona una estructura de árbol a la que se pueden
añadir múltiples recursos. Dado que los recursos se almacenan en dicha estructura de árbol,
pueden organizarse desde lo general (hacia la raíz del árbol) hasta lo específico (hacia las
hojas del árbol). Las consultas sobre un recurso específico buscarán automáticamente en la
jerarquía del recurso las reglas asignadas a los recursos ancestros, permitiendo una sencilla
herencia de reglas. Por ejemplo, si se desea aplicar una regla predeterminada a cada edificio
de una ciudad, bastaría con asignar la regla a la ciudad, en lugar de asignar la misma regla a
cada edificio. Sin embargo, algunos edificios pueden requerir excepciones a dicha regla, y esto
puede lograrse en Zend_Acl asignando dichas reglas de excepción a
cada edificio que las requiera. Un recurso puede heredar de un único recurso padre, aunque este
recurso padre puede tener a su vez su propio recurso padre, etc.
Zend_Acl también admite privilegios sobre los recursos (por
ejemplo, "create", "read", "update", "delete"), de modo que el desarrollador puede asignar
reglas que afecten a todos los privilegios o a privilegios específicos sobre uno o más recursos.
Al igual que con los recursos, crear un rol también es muy sencillo. Todos los roles deben
implementar Zend_Acl_Role_Interface. Esta interfaz consta de un
único método, getRoleId(). Adicionalmente,
Zend_Acl_Role es proporcionado por Zend_Acl como
una implementación básica de rol para que los desarrolladores la extiendan según lo necesiten.
En Zend_Acl, un rol puede heredar de uno o más roles. Esto es para
admitir la herencia de reglas entre roles. Por ejemplo, un rol de usuario, como "sally",
puede pertenecer a uno o más roles padres, como "editor" y "administrator". El
desarrollador puede asignar reglas a "editor" y "administrator" por separado, y "sally"
heredaría dichas reglas de ambos, sin necesidad de asignar reglas directamente a "sally".
Aunque la capacidad de heredar de múltiples roles es muy útil, la herencia múltiple
también introduce cierto grado de complejidad. El siguiente ejemplo ilustra la
condición de ambigüedad y cómo Zend_Acl la resuelve.
Ejemplo 12.1. Herencia múltiple entre roles
El siguiente código define tres roles base - "guest",
"member" y "admin" - de los cuales otros roles pueden
heredar. Luego, se establece un rol identificado como "someUser" que
hereda de los otros tres roles. El orden en que estos roles aparecen en el
array $parents es importante. Cuando sea necesario,
Zend_Acl busca reglas de acceso definidas no solo para el
rol consultado (en este caso, "someUser"), sino también para los roles de los que
el rol consultado hereda (en este caso, "guest", "member" y
"admin"):
$acl = new Zend_Acl();
$acl->addRole(new Zend_Acl_Role('guest'))
->addRole(new Zend_Acl_Role('member'))
->addRole(new Zend_Acl_Role('admin'));
$parents = array('guest', 'member', 'admin');
$acl->addRole(new Zend_Acl_Role('someUser'), $parents);
$acl->add(new Zend_Acl_Resource('someResource'));
$acl->deny('guest', 'someResource');
$acl->allow('member', 'someResource');
echo $acl->isAllowed('someUser', 'someResource') ? 'allowed' : 'denied';
Dado que no hay ninguna regla definida específicamente para el rol "someUser" y
"someResource", Zend_Acl debe buscar reglas que puedan estar
definidas para los roles de los que "someUser" hereda. Primero se visita el rol
"admin", y no hay ninguna regla de acceso definida para él. A continuación se visita
el rol "member", y Zend_Acl encuentra que hay una regla que
especifica que a "member" se le permite el acceso a "someResource".
Si Zend_Acl continuara examinando las reglas definidas para
otros roles padres, sin embargo, encontraría que a "guest" se le deniega el acceso a
"someResource". Este hecho introduce una ambigüedad porque ahora a
"someUser" se le deniega y se le permite el acceso a "someResource" a la vez, por haber
heredado reglas conflictivas de diferentes roles padres.
Zend_Acl resuelve esta ambigüedad completando una consulta cuando
encuentra la primera regla que es directamente aplicable a la consulta. En este caso,
dado que el rol "member" se examina antes que el rol "guest", el código de ejemplo
imprimiría "allowed".
![]() |
Nota |
|---|---|
Al especificar múltiples padres para un rol, tenga en cuenta que el último padre indicado es el primero en ser buscado para las reglas aplicables a una consulta de autorización. |
Una lista de control de acceso (ACL) puede representar cualquier conjunto de objetos físicos o virtuales que se desee. Sin embargo, para efectos de esta demostración, crearemos una ACL básica para un sistema de gestión de contenidos (CMS) que mantiene varios niveles de grupos sobre una amplia variedad de áreas. Para crear un nuevo objeto ACL, instanciamos la ACL sin parámetros:
$acl = new Zend_Acl();
![]() |
Nota |
|---|---|
Hasta que un desarrollador especifica una regla "allow", |
Los CMS casi siempre requerirán una jerarquía de permisos para determinar las capacidades de autoría de sus usuarios. Puede haber un grupo 'Guest' que permita un acceso limitado para demostraciones, un grupo 'Staff' para la mayoría de los usuarios del CMS que realizan la mayor parte de las operaciones cotidianas, un grupo 'Editor' para los responsables de publicar, revisar, archivar y eliminar contenido, y finalmente un grupo 'Administrator' cuyas tareas pueden incluir todas las de los demás grupos además del mantenimiento de información sensible, la gestión de usuarios, los datos de configuración internos, las copias de seguridad y la exportación. Este conjunto de permisos puede representarse en un registro de roles, permitiendo que cada grupo herede privilegios de los grupos 'padres', así como proporcionando privilegios distintos exclusivos para su propio grupo. Los permisos pueden expresarse de la siguiente manera:
Tabla 12.1. Controles de acceso para un CMS de ejemplo
| Nombre | Permisos únicos | Hereda permisos de |
|---|---|---|
| Guest | View | N/A |
| Staff | Edit, Submit, Revise | Guest |
| Editor | Publish, Archive, Delete | Staff |
| Administrator | (Se conceden todos los accesos) | N/A |
Para este ejemplo, se utiliza Zend_Acl_Role, pero cualquier objeto
que implemente Zend_Acl_Role_Interface es aceptable. Estos grupos
pueden añadirse al registro de roles de la siguiente manera:
$acl = new Zend_Acl();
// Add groups to the Role registry using Zend_Acl_Role
// Guest does not inherit access controls
$roleGuest = new Zend_Acl_Role('guest');
$acl->addRole($roleGuest);
// Staff inherits from guest
$acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);
/*
Alternatively, the above could be written:
$acl->addRole(new Zend_Acl_Role('staff'), 'guest');
*/
// Editor inherits from staff
$acl->addRole(new Zend_Acl_Role('editor'), 'staff');
// Administrator does not inherit access controls
$acl->addRole(new Zend_Acl_Role('administrator'));
Ahora que la ACL contiene los roles relevantes, se pueden
establecer reglas que definan cómo pueden acceder los roles a los recursos. Puede que
haya notado que no hemos definido ningún recurso en particular para este ejemplo, lo cual
se ha simplificado para ilustrar que las reglas se aplican a todos los recursos.
Zend_Acl proporciona una implementación mediante la cual las reglas
solo necesitan asignarse de lo general a lo específico, minimizando el número de reglas
necesarias, ya que los recursos y los roles heredan las reglas definidas en sus
ancestros.
![]() |
Nota |
|---|---|
En general, |
En consecuencia, podemos definir un conjunto razonablemente complejo de reglas con una cantidad mínima de código. Para aplicar los permisos base definidos anteriormente:
$acl = new Zend_Acl();
$roleGuest = new Zend_Acl_Role('guest');
$acl->addRole($roleGuest);
$acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);
$acl->addRole(new Zend_Acl_Role('editor'), 'staff');
$acl->addRole(new Zend_Acl_Role('administrator'));
// Guest may only view content
$acl->allow($roleGuest, null, 'view');
/*
Alternatively, the above could be written:
$acl->allow('guest', null, 'view');
//*/
// Staff inherits view privilege from guest, but also needs additional
// privileges
$acl->allow('staff', null, array('edit', 'submit', 'revise'));
// Editor inherits view, edit, submit, and revise privileges from
// staff, but also needs additional privileges
$acl->allow('editor', null, array('publish', 'archive', 'delete'));
// Administrator inherits nothing, but is allowed all privileges
$acl->allow('administrator');
Los valores NULL en las llamadas a allow()
anteriores se utilizan para indicar que las reglas de permiso se aplican a todos los recursos.
Ahora tenemos una ACL flexible que puede utilizarse para determinar
si los solicitantes tienen permiso para realizar funciones en toda la aplicación web.
Realizar consultas es bastante sencillo utilizando el método
isAllowed():
echo $acl->isAllowed('guest', null, 'view') ?
"allowed" : "denied";
// allowed
echo $acl->isAllowed('staff', null, 'publish') ?
"allowed" : "denied";
// denied
echo $acl->isAllowed('staff', null, 'revise') ?
"allowed" : "denied";
// allowed
echo $acl->isAllowed('editor', null, 'view') ?
"allowed" : "denied";
// allowed because of inheritance from guest
echo $acl->isAllowed('editor', null, 'update') ?
"allowed" : "denied";
// denied because no allow rule for 'update'
echo $acl->isAllowed('administrator', null, 'view') ?
"allowed" : "denied";
// allowed because administrator is allowed all privileges
echo $acl->isAllowed('administrator') ?
"allowed" : "denied";
// allowed because administrator is allowed all privileges
echo $acl->isAllowed('administrator', null, 'update') ?
"allowed" : "denied";
// allowed because administrator is allowed all privileges
![[Note]](images/note.png)