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;
}
llegué aquí buscando isMine(), que he intentado definir, pero parece que ya existe. –