cakephp 3 acl
Configuración de la base de datos de CakePHP ACL: estructura ARO/ACO? (1)
El sistema de ACL incorporado de CakePHP es realmente potente, pero está mal documentado en términos de detalles de implementación reales. Un sistema que hemos utilizado con cierto éxito en una serie de proyectos basados en CakePHP es el siguiente.
Es una modificación de algunos sistemas de acceso a nivel de grupo que se han documentado en otros lugares . Los objetivos de nuestro sistema son tener un sistema simple en el que los usuarios estén autorizados a nivel de grupo, pero pueden tener derechos adicionales específicos sobre los elementos que crearon ellos, o por usuario. Queríamos evitar tener que crear una entrada específica para cada usuario (o, más específicamente, para cada ARO) en la tabla aros_acos
.
Tenemos una tabla de Usuarios y una tabla de Roles.
Usuarios
user_id, user_name, role_id
Roles
id, role_name
Cree el árbol ARO para cada función (generalmente tenemos 4 roles: invitado no autorizado (id 1), usuario autorizado (id 2), moderador del sitio (id 3) y administrador (id 4):
cake acl create aro / Role.1
cake acl create aro 1 Role.2 ... etc ...
Después de esto, debe usar SQL o phpMyAdmin o similar para agregar alias para todos estos, ya que la herramienta de línea de comandos de tortas no lo hace. Usamos ''Role- {id}'' y ''User- {id}'' para todos los nuestros.
Luego creamos un ROOT ACO -
cake acl create aco / ''ROOT''
y luego crear ACO para todos los controladores bajo este ROOTO:
cake acl create aco ''ROOT'' ''MyController'' ... etc ...
Hasta ahora muy normal. Agregamos un campo adicional en la tabla aros_acos llamado _editown
que podemos usar como acción adicional en el actionMap del componente ACL.
CREATE TABLE IF NOT EXISTS `aros_acos` (
`id` int(11) NOT NULL auto_increment,
`aro_id` int(11) default NULL,
`aco_id` int(11) default NULL,
`_create` int(11) NOT NULL default ''0'',
`_read` int(11) NOT NULL default ''0'',
`_update` int(11) NOT NULL default ''0'',
`_delete` int(11) NOT NULL default ''0'',
`_editown` int(11) NOT NULL default ''0'',
PRIMARY KEY (`id`),
KEY `acl` (`aro_id`,`aco_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Luego podemos configurar el componente Auth para usar el método ''crud'', que valida el controlador / acción solicitada contra un AclComponent :: check (). En el app_controller tenemos algo parecido a:
private function setupAuth() {
if(isset($this->Auth)) {
....
$this->Auth->authorize = ''crud'';
$this->Auth->actionMap = array( ''index'' => ''read'',
''add'' => ''create'',
''edit'' => ''update''
''editMine'' => ''editown'',
''view'' => ''read''
... etc ...
);
... etc ...
}
}
De nuevo, esto es bastante estándar en las cosas de CakePHP. Luego, tenemos un método checkAccess en el AppController que agrega elementos a nivel de grupo para verificar si se debe verificar el ARO de un grupo o el ARO de usuario para acceder:
private function checkAccess() {
if(!$user = $this->Auth->user()) {
$role_alias = ''Role-1'';
$user_alias = null;
} else {
$role_alias = ''Role-'' . $user[''User''][''role_id''];
$user_alias = ''User-'' . $user[''User''][''id''];
}
// do we have an aro for this user?
if($user_alias && ($user_aro = $this->User->Aro->findByAlias($user_alias))) {
$aro_alias = $user_alias;
} else {
$aro_alias = $role_alias;
}
if (''editown'' == $this->Auth->actionMap[$this->action]) {
if($this->Acl->check($aro_alias, $this->name, ''editown'') and $this->isMine()) {
$this->Auth->allow();
} else {
$this->Auth->authorize = ''controller'';
$this->Auth->deny(''*'');
}
} else {
// check this user-level aro for access
if($this->Acl->check($aro_alias, $this->name, $this->Auth->actionMap[$this->action])) {
$this->Auth->allow();
} else {
$this->Auth->authorize = ''controller'';
$this->Auth->deny(''*'');
}
}
}
Los setupAuth()
y checkAccess()
se llaman en la devolución de llamada beforeFilter(
) de beforeFilter(
. También hay un método isMine
en AppControler (ver a continuación) que simplemente verifica que el ID_usuario del elemento solicitado sea el mismo que el usuario autenticado actualmente. Lo dejé por claridad.
Eso es todo lo que hay que hacer. A continuación, puede permitir / denegar el acceso de determinados grupos a acos -
cake acl grant ''Role-2'' ''MyController'' ''read''
cake acl grant ''Role-2'' ''MyController'' ''editown''
cake acl deny ''Role-2'' ''MyController'' ''update''
cake acl deny ''Role-2'' ''MyController'' ''delete''
Estoy seguro de que entiendes la imagen.
De todos modos, esta respuesta es más larga de lo que pretendía, y probablemente no tenga sentido, pero espero que sea de ayuda para ti ...
- editar -
Como se solicitó, aquí hay una edición (por pura claridad, hay un montón de cosas en nuestro código isMine()
que no tiene sentido aquí) isMine()
método de isMine()
que tenemos en nuestro AppController. También eliminé un montón de errores al verificar cosas, pero esta es la esencia de esto:
function isMine($model=null, $id=null, $usermodel=''User'', $foreignkey=''user_id'') {
if(empty($model)) {
// default model is first item in $this->uses array
$model = $this->uses[0];
}
if(empty($id)) {
if(!empty($this->passedArgs[''id''])) {
$id = $this->passedArgs[''id''];
} elseif(!empty($this->passedArgs[0])) {
$id = $this->passedArgs[0];
}
}
if(is_array($id)) {
foreach($id as $i) {
if(!$this->_isMine($model, $i, $usermodel, $foreignkey)) {
return false;
}
}
return true;
}
return $this->_isMine($model, $id, $usermodel, $foreignkey);
}
function _isMine($model, $id, $usermodel=''User'', $foreignkey=''user_id'') {
$user = Configure::read(''curr.loggedinuser''); // this is set in the UsersController on successful login
if(isset($this->$model)) {
$model = $this->$model;
} else {
$model = ClassRegistry::init($model);
}
//read model
if(!($record = $model->read(null, $id))) {
return false;
}
//get foreign key
if($usermodel == $model->alias) {
if($record[$model->alias][$model->primaryKey] == $user[''User''][''id'']) {
return true;
}
} elseif($record[$model->alias][$foreignkey] == $user[''User''][''id'']) {
return true;
}
return false;
}
Estoy luchando para implementar ACL en CakePHP. Después de leer la documentación en el manual del pastel , así como varios otros tutoriales, publicaciones en blogs, etc., encontré el excelente tutorial de Aran Johnson, que me ayudó a llenar muchos de los vacíos. Sus ejemplos parecen entrar en conflicto con otros que he visto en algunos lugares, específicamente en la estructura de árbol de ARO que usa.
En sus examples sus grupos de usuarios se configuran como un árbol en cascada, con el tipo de usuario más general en la parte superior del árbol y sus hijos ramificándose para cada tipo de acceso más restringido. En otras partes usualmente he visto cada tipo de usuario como un hijo del mismo tipo de usuario genérico.
¿Cómo configuras tus ARO y ACO en CakePHP? ¡Todos y cada uno de los consejos apreciados!