2008-09-10 7 views
21

Tengo dificultades para implementar ACL en CakePHP. Después de leer la documentación en el cake manual, así como varios otros tutoriales, publicaciones de blog, etc., encontré el excelente tutorial de Aran Johnson, que me ayudó a completar 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.Configuración de la base de datos ACL CakePHP: estructura ARO/ACO?

En su 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 restringido. En otras partes usualmente he visto cada tipo de usuario como un hijo del mismo tipo de usuario genérico.

¿Cómo se configuran sus ARO y ACO en CakePHP? ¡Todos y cada uno de los consejos apreciados!

+0

llegué aquí buscando isMine(), que he intentado definir, pero parece que ya existe. –

Respuesta

49

El sistema de ACL incorporado de CakePHP es realmente potente, pero está mal documentado en términos de detalles reales de implementación. 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 han sido documented elsewhere. 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

Crear el árbol ARO para cada función (por lo general con 4 funciones - no autorizado de visitantes (id 1), Autorizado Usuario (id 2), Site Moderator (id 3) y Administrator (id 4)):

cake acl create aro/Role.1

cake acl create aro 1 Role.2 ... etc ...

Después de esto, se tienen que utilizar SQL o phpMyAdmin o similar a agregar alias para todos ellos, ya que la herramienta de línea de comandos de la torta no lo hace. Usamos 'Role- {id}' y 'User- {id}' para todos los nuestros.

entonces se crea una ACO RAÍZ -

cake acl create aco/'ROOT'

y luego crear ACO para todos los controladores bajo esta raíz de una:

cake acl create aco 'ROOT' 'MyController' ... etc ...

Hasta aquí todo 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; 

Podemos a continuación, configurar el componente Auth utilizar el método 'porquería', que valida el controlador/acción solicitada contra un AclComponent :: verificación(). En el app_controller tenemos algo en la línea de:

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 ... 
    } 
} 

Una vez más, esto es bastante estándar cosas CakePHP. entonces tenemos un método checkAccess en el AppController que añade en la materia a nivel de grupo para comprobar si se debe comprobar un grupo ARO o un usuario ARO para el acceso:

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('*'); 
     } 
    } 
} 

El setupAuth() y checkAccess() métodos se llaman en el AppController ' s beforeFilter() devolución de llamada. 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 a determinados grupos específicos 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 obtiene la imagen.

De todos modos, el camino de esta respuesta más larga de lo que pretendía que fuera, y es probable que tenga al lado de ningún sentido, pero espero que sea alguna ayuda para usted ...

- editar -

Como se solicitó, aquí hay una edición (por pura claridad, hay un montón de cosas en nuestro código repetitivo que no tiene sentido aquí) isMine() método que tenemos en nuestro AppController. He quitado un montón de cosas comprobación de errores también, pero esta es la esencia de la misma:

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; 
} 
+1

:-) gracias por un gran tutorial. También me salvó .. :-) –

+0

simple y mejor que la mayoría de los artículos – aWebDeveloper

+0

@David: estoy usando cakephp 2.x y tratando de agregar algo como este cake acl create aco controllers Usuarios then cake acl create aco Users index Correr el 1er comando me dará error – anasanjaria

Cuestiones relacionadas