Difference between #4 and #5 of Introducción al control de acceso basado en roles (RBAC)

unchanged
Title
Introducción al control de acceso basado en roles (RBAC)
unchanged
Category
Tutorials
unchanged
Tags
rbac, authentication, control, acceso, basado, roles, tareas, operaciones, auth, AuthManager, CDbAuthManager
changed
Content
Todos los que hemos empezado a utilizar Yii para crear aplicaciones Web, nos
hemos dado de bruces cuando hemos intentado poner a funcionar el RBAC (acceso de
control basado en roles).

Unos por no tener conocimientos de como configurarlo, y otros porque una vez
configurado correctamente no entiende como funciona realmente.

Por ello, he creído necesario exponer mis escasos, pero efectivos,
conocimientos referentes al tema.

En primera instancia, no cabe duda que todos habéis leido el apartado
[Role-Based Access
Control](http://www.yiiframework.com/doc/guide/1.1/en/topics.auth#role-based-access-control
"Role-Based Access Control") de la guía definitiva de Yii. Sí, está
en inglés. Existe una traducción que hice en el
[FORO](http://www.yiiframework.com/forum/index.php?/topic/13948-control-de-acceso-basado-en-roles/
" Traducción de Role-Based Access Control") por si queréis leerla.

Creerme cuado os digo, que con sólo una lectura no basta para entender los
conceptos expuestos. Hay que experimentar para enterder los conceptos (como
siempre).

Una vez que hayáis leído (n veces) el apartado Role-Based Access Control,
pasamos a la configuración del RBAC.

### Como se configura RBAC.

Como habréis leído existen dos maneras de configurar RABC, una de ellas es
utilizando un script PHP para almacenar los datos, y, creo que la más `popular,
utilizando una base de datos para almacenarlos.

En esta pequeña guía vamos a basarnos en la opción de base de datos.

Bien, partimos de que todos conoceis, aunque sea un poco, la estructura de
directorios de vuestra aplicación.

Por si todavía no la conocéis, en el directorio "protected" existe
un directorio llamado "config" (este es el que os interesa de
momento), en él encontraréis un archivo cuyo nombre es "main.php".
Abrirlo con el editor que uséis normalmente.

Este archivo lo modificasteis para activar la configuración de la base de
datos. Y si todavía no lo habéis hecho, no os preocupéis, aun estáis a
tiempo.

Dependendiendo de si utilizáis SQLite o MySQL debereis comentar o descomentar
parte de código (la experiencia me ha dicho, que jamas borre código de un
archivo que se me ha proporcionado, no estoy didiendo que hagáis lo que yo
hago, sólo os doy un consejo):

Este bloque de código es para activar el uso de SQLite:

~~~
[php]
'db'=>array(
		'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
	),
~~~

Y este otro, es para el uso de MySQL:

~~~
[php]
'db'=>array(
		'connectionString' => 'mysql:host=localhost;dbname=mibasededatos',
		'emulatePrepare' => true,
		'username' => 'usuario',
		'password' => 'contrasenia',
		'charset' => 'utf8',
	),
~~~

Para los que aun no hayan configurado el acceso a base de datos, pueden hacerlo
ahora (comentando la parte de código que no va a usar y descomentando el
código que va a utilizar).

En este archivo colocaremos el código que se muestra a continuación, dicho
código será el encargado, por decirlo de algún modo, de activar el RBAC.

~~~
[php]
'authManager'=>array(
        'class'=>'CDbAuthManager',
        'connectionID'=>'db',
    ),
~~~

Ahora os queda la tarea de crear las tablas donde se almacenarán los datos.
Dentro del framework en el directorio "web" encontraréis un
directorio con el nombre "auth", en dicho directorio existe un archivo
llamado "schema.sql", el cual contiene un script SQL que creara las
tres tablas necesarias.

Para que no perdáis el tiempo en buscar el script, os lo coloco a
continuación:

~~~
[sql]
/**
 * Database schema required by CDbAuthManager.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @link http://www.yiiframework.com/
 * @copyright Copyright &copy; 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 * @since 1.0
 */

drop table if exists AuthAssignment;
drop table if exists AuthItemChild;
drop table if exists AuthItem;

create table AuthItem
(
   name                 varchar(64) not null,
   type                 integer not null,
   description          text,
   bizrule              text,
   data                 text,
   primary key (name)
);

create table AuthItemChild
(
   parent               varchar(64) not null,
   child                varchar(64) not null,
   primary key (parent,child),
   foreign key (parent) references AuthItem (name) on delete cascade on update
cascade,
   foreign key (child) references AuthItem (name) on delete cascade on update
cascade
);

create table AuthAssignment
(
   itemname             varchar(64) not null,
   userid               varchar(64) not null,
   bizrule              text,
   data                 text,
   primary key (itemname,userid),
   foreign key (itemname) references AuthItem (name) on delete cascade on update
cascade
);
~~~

Creo que todos sabréis ejecutar este escript, con lo que me salto este proceso.

Bien, ya tenemos todo lo necesario para empezar a utilizar el RBAC.

Para aquellos que os preguntáis si se pueden cambiar los nombres de las tablas
y los campos, deciros que sí, pero ojo, cambiar estos nombres conlleva cambiar
partes de código.

Cambiar los nombres de las tablas no conlleva mucho trabajo extra, pero el
cambio de los nombres de los campos os llevará mucho trabajo.

Para los que queráis cambiar el nombre de las tablas, simplemente añadir tres
líneas más en el código donde se activaba el RBAC. Tener en cuenta que los
nombres de las tablas creadas deben de coincidir con el nombre de las tablas en
la configuración:

~~~
[php]
'authManager'=>array(
        'class'=>'CDbAuthManager',
        'connectionID'=>'db',
		'itemTable'=>'AuthItem', // Tabla que contiene los elementos de
autorizacion
		'itemChildTable'=>'AuthItemChild', // Tabla que contiene los elementos
padre-hijo
		'assignmentTable'=>'AuthAssignment', // Tabla que contiene la signacion
usuario-autorizacion
    ),
~~~

Cambiar el nombre de los campos, es algo más complicado y no voy a entrar en
cómo llevarlo a cabo.

### Como funciona RBAC.

Bueno, ahora toca un poco de teoría. ¿Recordáis que elementos de
autorización existen? No os preocupéis, si no los recordáis, pero será
necesario que os lo vayáis aprendiendo: roles, tareas y operaciones.

En la guía se dice que un rol consiste en tareas, y estas consisten de
operaciones. Pues bien, eso es teoría. Realmente no existe una diferencia clara
entre roles, tareas y operaciones. Si, si, que en la teoría dicen que son cosas
diferentes, pero en realidad son conceptos diferentes de una misma cosa. La
diferenciación viene a explicar que se pueden crear elementos de autorización
dependientes de otros elementos de autorización. Pero como bien dice la guía
son elementos de autorización, se llamen como se llamen, eso es lo que nos
interesa. Elemento de autorización.

Una vez entendido esto, podeis crear la jerarquía que necesitéis. En algunas
aplicaciones puede bastar con tener solamente roles, sin necesidad de crear
autorizaciones detalladas (tareas y operaciones), por ejemplo distinguir entre
administradores y usuarios normales. Cuando vayais a diseñar vuestro esquema
jerarquizado, tener bien claro que necesidades teneis.

Como ya se ha dicho, existe la posibilidad de crear tareas para un rol,
operaciones de una tarea, e incluso operaciones de un rol (sin necesidad de
tener tareas). Esto vendría a ser un esquema en forma de árbol, pero Yii
permite que un rol sea parte de otro rol, que una tarea sea parte de otra tarea,
y que una operación sea parte de otra operación, con lo que la forma de árbol
deja de existir. Este esquema jerarquizado se denomina en la guía como una
jerarquía de autorización de orden parcial.

Bien, en dicho esquema se puede decir que hay elementos padre y elementos hijo.
Así que habrá herencia de autorización. Pero ¿quién hereda de quién? La
lógica y el sentido común diría que los hijos heredan del padre, pero en
nuestro caso es el padre el que hereda de los hijos. Suena raro, pero veamos un
ejemplo y lo veréis claramente.

**Nota:** No voy a entrar en detalles de como generar elementos de
autenticación, ni como asignarlos a usuarios mediante código, los ejemplos
aquí expuestos se pueden realizar introduciendo los datos directamente en las
tablas correspondientes. Cuando vayáis hacer uso de código para crear los
elementos y las asignaciones, la inserción en las tablas se hace
automáticamente. Lo que teneis que tener encuenta son dos cosas importantes:

1. Los tipos de elementos son numéricos 2-Rol, 1-Tarea, 0-Operación.

2. Los IDUsuario, no corresponde con la clave primaria de la tabla de Usuarios,
sino con el nombre que el usuario ha utilizado para acceder a la aplicación.

Supongamos que tenemos dos usarios, cada uno de ellos con un elemento de
autorización asignado, pero dichos elementos de autorización son padre e hijo:

~~~
[php]
Nombre Elemento | Tipo Elemento
--------------------------------
administrador   | 2 (Rol)
adminFinanciero | 1 (Operación)

Elemento Padre  | ElementoElemeto Hijo
---------------------------------
administrador   | adminFinanciero

IDUsuario  |  Elemento
-----------------------------
Usuario1   |  administrador
Usuario2   |  adminFinanciero
~~~


Y queremos controlar la autorización en la acción de mostrar un Cliente,
veamos como se comporta cada uno de los usuarios dependiendo de que
comprobación hagamos:

~~~
[php]
public function actionView($id)
{
	if (Yii::app()->user->checkAccess("administrador"))
	{
		echo 'HOLA';
	} else {
		echo 'ADIOS';
	}
}
~~~


Si el usuario activo es Usuario1 mostraría: HOLA

Si el usuario activo es Usuario2 mostraría: ADIOS

~~~
[php]	
public function actionView($id)
{
	if (Yii::app()->user->checkAccess("adminFinanciero"))
	{
		echo 'HOLA';
	} else {
		echo 'ADIOS';
	}
}
~~~


Si el usuario activo es Usuario1 mostraría: HOLAADIOS

Si el usuario activo es Usuario2 mostraría: HOLA

Recordar que hemos dicho que el padre hereda del hijo. Podríamos decirlo de
otra manera, el padre es capaz de hacer todo lo que hacen sus hijos. O de otra
manera, el elemento padre delega en los elementos hijos, pero no pierde la
virtud de la delegación.

Espero que cualquiera de las anteriores definiciones os aclaren como funciona la
herencia en RBAC.

Una vez aclarada la herencia pasemos a explicar dónde se debe de comprobar el
acceso. Bueno, pues puede ser en el controlador o en la vista. Depende de que
queramos hacer, si lo que queremos, por ejemplo, es mostrar u ocultar opciones
de un menú, está claro que debe ser en la vista. Pero si lo que queremos es
controlar las acciones, deberemos utilizar el controlador, valga la redundancia.

Vale, algunos de vosotros os preguntaréis, ¿tenemos que escribir los
condicionales de los ejemplos anteriores en todas las acciones del controlador?
Pues depende de que quereis hacer, si lo que buscáis es que si tiene permiso
ejecute la acción y si no tiene permiso deniegue la acción, lo más simple es
hacer la comprobación en la "accessRules" del controlador. Si eso es
lo que necesitáis, a continuación tenéis un ejemplo:

~~~
[php]
public function accessRules()
	{
		return array(
			array('allow',
				'actions'=>array('index'),
				'users'=>array('?'),
			),
			array('allow',
				'actions'=>array('view'),
				'users'=>array('@'),
			),
			array('allow',
				'actions'=>array('create','update','admin','delete'),
				'expression'=>'Yii::app()->user->checkAccess("adminFinanciero")',
			),
			array('deny',
				'users'=>array('*'),
			),
		);
	}
~~~

Veamos el ejemplo con detenimiento. A los usuarios no logueados (visitantes) se
les permite la acción INDEX y se deniegan todas las demás, a los logueados
(usuarios registrados) se les permite las acciones INDEX y VIEW, mientras que se
les deniega el resto de acciones. A los usuarios que tengan el elemento de
autenticación "adminFinanciero" asignado (directa o indirectamente)
tendrán acceso a las acciones INDEX, VIEW, CREATE, UPDATE, ADMIN y DELETE; y se
les deniega el resto de acciones (si las hubiera).

Pues con esto, voy a dar por terminado este pequeño artículo introductorio al
RBAC.

Espero que sirva a más de uno para aclarar ideas, pero con que le sirva a uno
sólo me doy por satisfecho.

Nos vemos en otros artículos.