En el presente ejemplo se va a hacer uso de los componentes Acl,
Auth y los
plugins de los Controladores
para implementar un sencillo modelo de seguridad para un "Blog".
El ejemplo se centra en los aspectos de seguridad del "Blog" y no en publicar ó visulizar los "posts" del mismo.
Crear una lista de control ACL
Usaremos un Acl para definir una lista de control de acceso basada en una tabla de MySQL.
La tabla se llamará "access_list" y tiene la siguiente estructura:
CREATE TABLE `access_list` (
`id` int(11) NOT NULL auto_increment,
`role` varchar(24) NOT NULL,
`resource` varchar(32) NOT NULL,
`action` varchar(32) NOT NULL,
`allow` char(1) default NULL,
PRIMARY KEY (`id`),
KEY `role_1` (`role`,`resource`,`action`),
KEY `role_2` (`role`,`resource`,`action`,`allow`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Recursos a Controlar
Nuestra aplicación de "blog" tiene 3 controladores que actúan como "recursos" y una serie de "acciones"
relacionadas a estos:
Nombre Recurso
Descripción
Acciones
SesionController
Permite iniciar y terminar sesión a los administradores
index
entrar
salir
PostsController
Muestra los posts creados hasta el momento
index
detalles
AdminController
Permite crear, consultar, editar y eliminar los posts del blog
index
crear
editar
buscar
eliminar
Roles del Blog
El "blog" tiene 2 roles, se describen a continuación:
Nombre Rol
Descripción
Visitante
Este Rol es usado por defecto y se usado por los lectores del blog.
Administrador
Este rol es usado por los administradores del blog, quienes tienen derecho
a crear, modificar, borrar, etc los posts.
Agregar los permisos a la lista de control
Insertamos los siguientes registros a la tabla "access_list" para indicar los permisos asignados a cada rol:
//El "Visitante" no tiene acceso a:
INSERT INTO `access_list` VALUES ("Visitante", "admin", "index", "N");
INSERT INTO `access_list` VALUES ("Visitante", "admin", "crear", "N");
INSERT INTO `access_list` VALUES ("Visitante", "admin", "editar", "N");
INSERT INTO `access_list` VALUES ("Visitante", "admin", "eliminar", "N");
INSERT INTO `access_list` VALUES ("Visitante", "admin", "buscar", "N");
INSERT INTO `access_list` VALUES ("Visitante", "sesion", "salir", "N");
//El "Administrador" tiene acceso a todo
INSERT INTO `access_list` VALUES ("Administrador", "*", "*", "Y");
Crear una tabla de usuarios
Los usuarios administradores se almacenan también en la siguiente tabla junto con su rol:
CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`login` varchar(32) NOT NULL,
`password` char(40) NOT NULL,
`role` varchar(24) default NULL
PRIMARY KEY (`id`),
KEY `users_1` (`login`, `password`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
//Crear algunos usuarios
INSERT INTO `users` VALUES ("admin", "7df2a311e10899e9fc79f6b8f6b91297", "Administrador");
INSERT INTO `users` VALUES ("carolina", "88f1798e205c841fe851b42095329f84", "Administrador");
Implementar el controlador SesionController
Este controlador permitirá iniciar sesión y mantener la identidad del usuario. La acción entrar
hace uso del componente Auth
para realizar esta tarea:
<php
// apps/default/controllers/sesion_controller.php
class SesionController extends ApplicationController {
public function indexAction(){
//Aqui muestra el formulario de inicio de sesion
}
public function entrarAction(){
//Obtener datos del formulario, encriptar password con sha1
$login = $this->getPostParam("login", "addslaches");
$password = sha1($this->getPostParam("password"));
//Usar Auth para comprobar identidad en el modelo "Users"
$auth = new Auth(array(
"model",
"class" => "Users",
"login" => $login,
"password" => $password
));
//Si las credenciales son validas ir a admin/index
if($auth->authenticate()==true){
Router::routeTo(array(
"controller" => "admin",
"action" => "index"
));
} else {
//Si el usuario/password son inválidos volver a sesion/index
Router::routeTo(array(
"controller" => "sesion",
"action" => "index"
));
}
}
public function salirAction(){
//Destruir identidad activa y volver al sesion/index
Auth::destroyIdentity();
Router::routeTo(array("controller" => "sesion", "action" => "index"));
}
}
Controlar el Acceso a los Recursos de la Aplicación
Cada vez que se ingrese a una acción en un controlador debemos validar que el usuario activo
tenga acceso a la misma. Esto lo podemos hacer de forma sencilla implementando un plugin de controladores
que ejecute un evento antes de cada acción:
<php
// apps/default/plugins/permisos.php
class PermisosPlugin extends ControllerPlugin {
/**
* Lista de permisos ACL
*
* @var Acl
*/
private $_acl;
/**
* Obtener el ACL al inicializar el Plugin
*
*/
public function __construct(){
$this->_acl = new Acl("Model", "className: AccessList");
}
public function beforeDispatch(){
//Si hay un usuario activo se obtiene el rol
if(Auth::isValid()==true){
$identidad = Auth::getActiveIdentity();
$rol = $identidad["role"];
} else {
$rol = "Visitante";
}
//Obtener recurso y acción activa
$recurso = Router::getController();
$accion = Router::getAction();
//Si no tiene permiso se enruta al controlador "sesion"
$tienePermiso = $this->_acl->isAllowed($rol, $recurso, $accion);
if($tienePermiso==false){
Router::routeTo(array(
"controller" => "sesion",
"action" => "index"
));
}
}
}
Notése que con solo hacer un enrutamiento al controlador sesión se evita que se ejecute
la acción solicitada sino tiene permiso para esta.
Conclusiones
Los plugins de controladores permiten ejecutar procedimientos en cada enrutamiento a un controlador/acción, esto
los hace muy adecuados para tareas como el control de acceso y seguridad.
Al usar plugins de controladores se evita agregar código traversal a la aplicación haciendo
cada controlador más limpio.
Listas de control de acceso y usuarios pueden ser administrados usando tablas y modelos de una
base de datos
Tell friends about this article on social networks: