Simple Acl en CakePHP



Acl en CakePHP
Ejecute las siguientes instrucciones SQL en la base de datos:
CREATE TABLE users (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL UNIQUE,
    password CHAR(40) NOT NULL,
    group_id INT(11) NOT NULL,
    created DATETIME,
    modified DATETIME
);
 
CREATE TABLE groups (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    created DATETIME,
    modified DATETIME
);
 
CREATE TABLE posts (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    user_id INT(11) NOT NULL,
    title VARCHAR(255) NOT NULL,
    body TEXT,
    created DATETIME,
    modified DATETIME
); 

Preparativos para añadir autenticación
Ahora tenemos una aplicación CRUD funcionamiento. Bake debe tener la configuración de todas las relaciones que necesitamos, si no añadirlos en este momento. Hay algunas otras piezas que necesitan ser añadido antes de que podamos añadir los componentes Auth y Acl. Primero se debe agregar un inicio de sesión y cierre de sesión de acción para su UsersController:

public function login() {
    if ($this->request->is('post')) {
        if ($this->Auth->login()) {
            return $this->redirect($this->Auth->redirectUrl());
        }
        $this->Session->setFlash(__('Your username or password was incorrect.'));
    }
}
 
public function logout() {
    //Leave empty for now.
}

A continuación, cree el archivo de vista siguiente de inicio de sesión en app /view/users/login.ctp:

<?php
echo $this->Form->create('User', array('action' => 'login'));
echo $this->Form->inputs(array(
    'legend' => __('Login'),
    'username',
    'password'
));
echo $this->Form->end('Login');
?>

El almacenamiento de contraseñas en texto plano es extremadamente inseguro y AuthComponent esperará que sus contraseñas se hash. En app/model/user.php añadir lo siguiente:

App::uses('AuthComponent', 'Controller/Component');
class User extends AppModel {
    // other code.
 
    public function beforeSave($options = array()) {
        $this->data['User']['password'] = AuthComponent::password(
          $this->data['User']['password']
        );
        return true;
    }
}

Como queremos todo nuestro sitio controlado con autenticación y ACL, vamos a ponerlos en AppController:

class AppController extends Controller {
    public $components = array(
        'Acl',
        'Auth' => array(
            'authorize' => array(
                'Actions' => array('actionPath' => 'controllers')
            )
        ),
        'Session'
    );
    public $helpers = array('Html', 'Form', 'Session');
 
    public function beforeFilter() {
        //Configure AuthComponent
        $this->Auth->loginAction = array(
          'controller' => 'users',
          'action' => 'login'
        );
        $this->Auth->logoutRedirect = array(
          'controller' => 'users',
          'action' => 'login'
        );
        $this->Auth->loginRedirect = array(
          'controller' => 'posts',
          'action' => 'add'
        );
    }
}

Antes de configurar la ACL del todo tendremos que añadir algunos usuarios y grupos. Con AuthComponent en uso no vamos a ser capaces de acceder a cualquiera de nuestras acciones, ya que no se ha identificado. Ahora vamos a añadir algunas excepciones para AuthComponent nos permitirá crear algunos grupos y usuarios. En tanto su GroupsController y su UsersController Añadir el siguiente:

public function beforeFilter() {
    parent::beforeFilter();
 
    // For CakePHP 2.0
    $this->Auth->allow('*');
 
    // For CakePHP 2.1 and up
    $this->Auth->allow();
}

Estas declaraciones dicen AuthComponent para permitir el acceso público a todas las acciones. Esto es sólo temporal y se eliminará una vez que tengamos unos usuarios y grupos en nuestra base de datos. No agregue los usuarios o grupos por el momento sin embargo.
Inicializar las tablas Acl Db
Antes de crear los usuarios o grupos querremos conectarlos con el Acl. Sin embargo, no tenemos en este momento tenemos ninguna tabla Acl y si intenta ver las páginas en este momento, obtendremos un error de tabla que falta ("Error: No se encontró acos tabla de base de datos para el modelo de Aco."). Para eliminar estos errores necesitamos ejecutar:
$ cake schema create DbAcl

Este esquema le pedirá que deje caer y crear las tablas. Acepta la eliminación y la creación de las tablas.
Si usted no tiene acceso a una consola, o tiene algún problema usando la consola, puede ejecutar el archivo sql encontrado en /app/Config/Schema/db_acl.sql.

Actúa como un Solicitante
Para autenticación y Acl funcionen correctamente tenemos que asociar nuestros usuarios y grupos a filas en las tablas de ACL. Para hacer esto usaremos el AclBehavior. El AclBehavior permite la conexión automagic de modelos con las tablas Acl. Su uso requiere una implementación de parentNode() en su modelo. En nuestra modelo User añadiremos lo siguiente:

class User extends AppModel {
    public $belongsTo = array('Group');
    public $actsAs = array('Acl' => array('type' => 'requester'));
 
    public function parentNode() {
        if (!$this->id && empty($this->data)) {
            return null;
        }
        if (isset($this->data['User']['group_id'])) {
            $groupId = $this->data['User']['group_id'];
        } else {
            $groupId = $this->field('group_id');
        }
        if (!$groupId) {
            return null;
        }
        return array('Group' => array('id' => $groupId));
    }
}

Luego, en nuestro modelo Group agregue:

class Group extends AppModel {
    public $actsAs = array('Acl' => array('type' => 'requester'));
 
    public function parentNode() {
        return null;
    }
}

¿Qué hace esto, está vinculada al Grupo y usuario modelos a la ACL, y decirle a CakePHP que cada vez que haga un usuario o grupo que desee una entrada en la tabla aros también. 

ACL-único grupo
En caso de que queramos simplificados sólo permisos por grupo, tenemos que poner en práctica bindNode() en el modelo user:

public function bindNode($user) {
    return array('model' => 'Group', 'foreign_key' => $user['User']['group_id']);
}

A continuación, modifique los actsAs para el modelo user y desactivar la directiva solicitante:

public $actsAs = array('Acl' => array('type' => 'requester', 'enabled' => false));

Nota: Cada usuario tiene que haber group_id asignado para que esto funcione.
Ahora el aros tabla se verá así:

+----+-----------+-------+-------------+-------+------+------+
| id | parent_id | model | foreign_key | alias | lft  | rght |
+----+-----------+-------+-------------+-------+------+------+
|  1 |      NULL | Group |           1 | NULL  |    1 |    2 |
|  2 |      NULL | Group |           2 | NULL  |    3 |    4 |
|  3 |      NULL | Group |           3 | NULL  |    5 |    6 |
+----+-----------+-------+-------------+-------+------+------+
3 rows in set (0.00 sec)



Creación de ACO (Access Control Objects)
Ahora que tenemos nuestros usuarios y grupos (aros), podemos empezar a ingresar nuestros controladores en el Acl y fijar los permisos para nuestros grupos y usuarios, así como permitir login / logout.
Nuestra ARO están creando automáticamente a sí mismos cuando se crean nuevos usuarios y grupos. ¿Qué pasa con una forma de auto-generar ACO desde nuestros controladores y sus acciones? Bueno, lamentablemente no hay forma mágica en el núcleo de CakePHP para lograr esto. Las clases del núcleo ofrecen unas pocas formas de crear manualmente pesar de ACO. Puede crear objetos ACO de la cáscara Acl o Puede utilizar la AclComponent. 

$ cake acl create aco root controllers

Si bien desde el AclComponent se verá como:
$this->Acl->Aco->create(array('parent_id' => null, 'alias' => 'controllers'));
$this->Acl->Aco->save();

Ambos ejemplos crearía nuestra 'root' o nivel superior ACO que va a ser llamado 'controladores'. El propósito de este nodo raíz es para hacer más fácil para permitir / denegar el acceso en un ámbito de aplicación mundial, y permitir el uso del Acl para fines no relacionados con los controladores / acciones como la comprobación de permisos de registro del modelo.

Como vamos a utilizar un ACO raíz global tenemos que hacer una pequeña modificación en nuestro AuthComponent configuración. AuthComponent necesita saber acerca de la existencia de este nodo raíz, por lo que al hacer ACL comprueba que puede utilizar la ruta de nodo correcto al buscar controladores / acciones. En AppController asegurar que su componentes $ array contiene el actionPath definido anteriormente:

class AppController extends Controller {
    public $components = array(
        'Acl',
        'Auth' => array(
            'authorize' => array(
                'Actions' => array('actionPath' => 'controllers')
            )
        ),
        'Session'
    );

 

Sencilla aplicación controlada Acl - parte 2

Una herramienta automática para crear ACOs

Como se mencionó antes, no hay manera de pre-construidos a la entrada de todos nuestros controladores y acciones en la ACL. Sin embargo, todos odiamos hacer cosas repetitivas como escribir en lo que podría haber cientos de acciones en una aplicación grande.
Para ello existe un plugin muy útil disponible en GitHub, llamado AclExtras que se puede descargar en la página de GitHub Descargas. Vamos a describir brevemente cómo utilizarla para generar toda nuestra ACO de
En primer lugar tomar una copia del plugin y descomprimido o clonar usando git en app/Plugins/AclExtras. Luego activar el plugin como se muestra a continuación:

//app/Config/boostrap.php
// ...
CakePlugin::load('AclExtras');


Configuración de permisos

A fin de permitir a la AclComponent usaríamos la siguiente sintaxis de código en un método personalizado:
$this->Acl->allow($aroAlias, $acoAlias);

Agregue lo siguiente a una función temporal en su UsersController 

public function beforeFilter() {
    parent::beforeFilter();
    $this->Auth->allow('initDB'); // We can remove this line after we're finished
}
 
public function initDB() {
    $group = $this->User->Group;
 
    // Allow admins to everything
    $group->id = 1;
    $this->Acl->allow($group, 'controllers');
 
    // allow managers to posts and widgets
    $group->id = 2;
    $this->Acl->deny($group, 'controllers');
    $this->Acl->allow($group, 'controllers/Posts');
    $this->Acl->allow($group, 'controllers/Widgets');
 
    // allow users to only add and edit on posts and widgets
    $group->id = 3;
    $this->Acl->deny($group, 'controllers');
    $this->Acl->allow($group, 'controllers/Posts/add');
    $this->Acl->allow($group, 'controllers/Posts/edit');
    $this->Acl->allow($group, 'controllers/Widgets/add');
    $this->Acl->allow($group, 'controllers/Widgets/edit');
 
    // allow basic users to log out
    $this->Acl->allow($group, 'controllers/users/logout');
 
    // we add an exit to avoid an ugly "missing views" error message
    echo "all done";
    exit;
}
Ahora hemos establecido algunas reglas básicas de acceso. Hemos permitido que los administradores a todo. Los administradores pueden acceder a todo en los puestos y widgets. Mientras que los usuarios sólo pueden acceder a añadir y editar en los puestos y widgets.

Iniciar sesión

Agregue lo siguiente a app /View/Users/login.ctp si no lo ha hecho:

<h2>Login</h2>
<?php
echo $this->Form->create('User', array(
    'url' => array(
        'controller' => 'users',
        'action' => 'login'
    )
));
echo $this->Form->input('User.username');
echo $this->Form->input('User.password');
echo $this->Form->end('Login');
 
Si un usuario ya está conectado, le redirigir añadiendo esto a su UsersController:
public function login() {
    if ($this->Session->read('Auth.User')) {
        $this->Session->setFlash('You are logged in!');
        return $this->redirect('/');
    }
}

Ahora debería ser capaz de iniciar sesión y todo debe trabajar auto-mágicamente. Cuando se mostrarán Acceso denegado mensajes Auth si se ha añadido la echo $ this-> Session-> flash ('auth')

 

Cerrar sesion

Ahora sobre el cierre de sesión. Más temprano salimos de esta función en blanco, ahora es el momento para llenarlo. En UsersController :: logout () añade lo siguiente:

$this->Session->setFlash('Good-Bye');
$this->redirect($this->Auth->logout());

Esto establece un mensaje flash de sesión y cierra la sesión del usuario, utilizando el método de cierre de sesión de autenticación. Método de cierre de sesión de autenticación básicamente elimina la clave de sesión de autenticación y devuelve un URL que se puede utilizar en una redirección. Si hay otros datos de sesión que necesita ser eliminado, así que añadir código aquí.

Todo listo

Ahora debería tener una aplicación controlada por autenticación y ACL. Usuarios permisos se establecen a nivel de grupo, pero puede ponerlos por el usuario a la vez. También puede establecer permisos en una global y per-controlador y por acción base. Además, tiene un bloque reutilizable de código para ampliar fácilmente su mesa ACO como su aplicación crece.


Comentarios