Despabilando la MonoNeurona::Internet es de todos [Inicio] [Regresar]
Desarrollo \ othAuth, users and permissions on CakePHP
Desarrollo
othAuth, users and permissions on CakePHP

Este artículo ha sido consultado en 1,730 ocasiones.

othAuth es una solución de manejo de permisos en el framework CakePHP, está desarrollada por Othman ouahbi aka "CraZyLeGs", un chico que (me parece) vive y trabaja en la India.

En el manual de CakePHP se explica el Access Contro List (ACL) la Lista de Control de Acceso. Las ACL se forman de usuarios y grupos de usuarios con diferentes permisos, por ejemplo sólo los usuarios del grupo "admin" pueden ver y modificar la información general de Karamelo. ACL es muy potente y flexible y utiliza conceptos que se usan en los permisos de archivos de Linux.

othAuth implementa la ACL de CakePHP en algunas vistas del programa que se está desarrollando. othAuth se usa tanto en Centauro como en Karamelo. othAuth es muy sencillo de usar y  se conforma de un componente el cual se debe descargar en app/controllers/components/oth_auth.php y de un helper que se coloca en app/views/helpers/oth_auth.php.

Antes que nada debemos recordar que en el archivo app/config/core.php se pueden configurar algunas cosas de CakePHP. En este caso nos interesa la definición de la constante:

define('CAKE_ADMIN', 'admin');


está constante debe estar descomentada para que surga efecto, concretamente lo que esta constante hace es definir la ruta de las pantallas de administración. Generalnmente estas vistas son de acceso restringido y sólo los usuaros logeados (y que pertenecen al grupo correcto) pueden verlas.  Es decir si tenemos un URL como /admin/users/edit significa que tenemos un método admin_edit en el controlador app/controllers/users_controller.php y una vista en app/views/users/admin_edit.thtml.

Es decir, los métodos en el controlador que corresponden a la zona admin tienen el prefijo admin_ :
admin_delete(), admin_add(), admin_listing(), etcétera. Estos métodos del controlador son de acceso restringido y othAuth nos ayuda a restringir el paso.

Para usar othAuth necesitamos cuatro tablas: users, groups, permissions, groups_permissions. En la documentación está el SQL para crearlas en MySQL pero nosotros estamos usando PostgreSQL con nuestro propio script. Además nosotros necesitamos algunas columnas extras en la tabla "users". Como sea el resultado es que tenemos las mismas columnas que necesita othAuth.

Las tablas se usan de manera muy simple, creamos la tabla "groups":

CREATE TABLE groups ( -- the users groups to Auth
id serial PRIMARY KEY,
name character varying(50) NOT NULL,
"level" integer NOT NULL,
redirect character varying(50) NOT NULL,
perm_type character varying(10) DEFAULT 'allow'::character varying NOT NULL,
created timestamp(0) with time zone DEFAULT now() NOT NULL,
modified timestamp(0) with time zone DEFAULT now() NOT NULL,
CHECK (perm_type IN ('allow', 'denied'))
);

Luego agregamos uno o más grupos en la tabla "groups", en el caso de Centauro sólo tenemos dos grupos, "admin" y "users":

INSERT INTO groups ("name", "level", "perm_type", "redirect") VALUES ('admin',   100, 'allow', '/news/view');
INSERT INTO groups ("name", "level", "perm_type", "redirect") VALUES ('users',   200, 'allow', '/news/view');

El campo "redirect" indica donde se debe redireccionar al usuario después de logeado.

Ahora creamos la tabla "users":

CREATE TABLE users (
id serial PRIMARY KEY,
username character varying(50) DEFAULT ''::character varying NOT NULL UNIQUE, --login
passwd character varying(32) DEFAULT ''::character varying NOT NULL,
name character varying(50) DEFAULT ''::character varying NOT NULL, --real name
email character varying(45) DEFAULT ''::character varying NOT NULL UNIQUE,
last_visit timestamp(0) with time zone DEFAULT now() NOT NULL,
group_id integer NOT NULL, -- Admin, normal user
created timestamp(0) with time zone DEFAULT now() NOT NULL,
modified timestamp(0) with time zone DEFAULT now() NOT NULL,
website character varying(500),
cv text,
lang_id int REFERENCES langs(id) ON DELETE CASCADE NOT NULL DEFAULT 9, -- english by default
avatar character varying(100) DEFAULT 'default-avatar.jpg'::character varying NOT NULL,
"quote" character varying(150),
name_blog character varying(150),
license_id int REFERENCES licenses(id) ON DELETE CASCADE NOT NULL DEFAULT 6,
livechat int NOT NULL DEFAULT 1,
wiwd int NOT NULL DEFAULT 1, -- what I was doing
active int NOT NULL DEFAULT 0, -- active =1, desactived = 0
tags text NOT NULL DEFAULT 'arts, music, hacking, environment, education, cars'
);

El campo group_id indica a que grupos peretence el usuario, en nuestro caso sí³lo puede pertenecer al grupo "admin" (group_id=1) o a "users" (group_id=2). Como señalamos antes, esta tabla tiene más columnas que la que tiene la tabla "users" de la documentación de othAuth porque nosotros necesitamos informacií³n extra. Ahora agregamos un usuario a la tabla users:

-- passwd = "admin"
INSERT INTO users("username", "passwd", "name",
"email",
"group_id",
"active",
"website",
"cv",
"quote",
"name_blog",
"avatar")
VALUES ('webmaster',
'21232f297a57a5a743894a0e4a801fc3',
'John Smith',
'john@site.edu',
1,
1,
'http://www.chipotle-software.com',
'Psychology and art teacher, travel and long walks lover. A life fueled by the magic bean, "Coffee".',
'"Nonviolence is a weapon of the strong", Gandhi',
'The Lost Forest', -- name blog
'HappyShark.jpg' --avatar
);

El usuario "webmaster" pertenece al grupo "admin" y su password en md5 es "admin".

Bien ahora vamos a crear la tabla de permisos, "permissions":

CREATE TABLE permissions (
id serial PRIMARY KEY,
name character varying(50) DEFAULT ''::character varying NOT NULL,
created timestamp(0) with time zone DEFAULT now() NOT NULL,
modified timestamp(0) with time zone DEFAULT now() NOT NULL
);

Agregamos algunos permisos:

--Blog entries
INSERT INTO permissions (id, name) VALUES (13, 'admin/entries/add');
INSERT INTO permissions (id, name) VALUES (14, 'admin/entries/edit');
INSERT INTO permissions (id, name) VALUES (15, 'admin/entries/delete');
INSERT INTO permissions (id, name) VALUES (16, 'admin/entries/listing');
INSERT INTO permissions (id, name) VALUES (17, 'admin/entries/start');

Es decir el URL 'admin/entries/add' tiene el permiso 13, 'admin/entries/edit' el 14, 'admin/entries/delete' el 15, etcétera. Estos permisos existen pero no los posee ningíºn grupo (y por lo tanto ningíºn usuario).

Vincular los permisios con los grupos de usuarios es precisamente lo que hace la tabla "groups_permissions" que creamos así­:

CREATE TABLE groups_permissions (
group_id int REFERENCES groups(id) ON DELETE CASCADE,
permission_id int REFERENCES permissions(id) ON DELETE CASCADE,
PRIMARY KEY (group_id, permission_id)
);

Ahora le damos permisos al grupo 1 (admin) a los URL del 13 al 17:

INSERT INTO groups_permissions (group_id, permission_id) VALUES (1, 13);
INSERT INTO groups_permissions (group_id, permission_id) VALUES (1, 14);
INSERT INTO groups_permissions (group_id, permission_id) VALUES (1, 15);
INSERT INTO groups_permissions (group_id, permission_id) VALUES (1, 16);
INSERT INTO groups_permissions (group_id, permission_id) VALUES (1, 17);

Esto quiere decir que el usuario "webmaster" ahora tiene permisos CRUD (create, read, update and delete) para los métodos admin_add, admin_edit y admin_delete del controlador app/controllers/entries_controller.php. Tiene estos permisos porque pertenece al group_id que es igual a "1". (El URL 'admin/entries/start' es sólo el homepage de la zona admin y no es importante).

Para darle permisos a los usuarios del grupo "users" tendrí­amos que vincular el id del permiso con el id del grupo "users":

INSERT INTO groups_permissions (group_id, permission_id) VALUES (2, 13);
INSERT INTO groups_permissions (group_id, permission_id) VALUES (2, 14);
INSERT INTO groups_permissions (group_id, permission_id) VALUES (2, 15);
INSERT INTO groups_permissions (group_id, permission_id) VALUES (2, 16);
INSERT INTO groups_permissions (group_id, permission_id) VALUES (2, 17);

Sencillo ¿no?, Necesitamos el archivo app/models/group.php para la tabla "groups":

class Group extends AppModel
{
var $name = 'Group';
var $hasMany = 'User';
var $hasAndBelongsToMany = array('Permission' =>
array('className' => 'Permission',
'joinTable' => 'groups_permissions')
);
}
?>

En el archivo app/app_controller.php necesitamos agregar el array público $othAuthRestrictions:

public $othAuthRestrictions = array('admin_add','admin_edit','admin_delete', 'admin_listing', 'admin_start');

Este arregalo le indica a othAuth cuáles métodos en los controladores de nuestro programa deben ser revisados antes de presentarlos, esto  para checar que el usuario realmente tenga permisos.

Dentro del método beforeFilter() de app_controller.php debemos declarar el arreglo $auth_conf, este arreglo configura algunas opciones de ohAuth:

$auth_conf = array(
    'mode' => oth',
    'login_page' => '/users/login',
    'logout_page' => '/users/logout',
    'access_page' => '/news/view',
   'hashkey' => 'mYpERsOn78787ALhaSHkeY',
   'noaccess_page' => '/users/noaccess',
   'strict_gid_check' => true
);

$this->othAuth->controller = &$this; // controlleret
$this->othAuth->init($auth_conf);
$this->othAuth->check();

Al estar en beforeFilter() de app_controller.php, othAuth se ejecuta antes que el método para revisar la seguridad.  Además como se indica en a documnetación, el método unbindAll() se debe colocar en app/app_model.php para que othAth no tenga que lidiar con arreglos demasiado grandes.

Como indicamos en el array$auth_conf, la página donde los usuarios se logean es /users/login, es decir debemos tener un método login en el controlador users_conroller.php :

public function login()
{
    $this->pageTitle = 'Login :: Centauro';
   
    $this->set('Element', $this->Portal->statics());

    if (isset($this->data['User']))
    { 
    $auth_num = $this->othAuth->login($this->data['User']);
   
    $this->set('auth_msg', $this->othAuth->getMsg($auth_num));
}

Este método revisa que el login y la contraseña que el usuario puso en el formulario de logeo  sean los correctos, si es así othAuth inicia una sesión y asigna los permisos definidos en la tabla groups_permissions al usuario que se acaba de logear.

Una vez que el usuario se ha logeado podemos recuperar su información con el componente oth_auth.php, por ejemplo en cualquier controlador podemos pintar la info del usuario:

echo "El id del usuario es "                 . $this->othAuth->user('id')                 . "BR";
echo "El username del usuario es "  . $this->othAuth->user('username')  . "BR";
echo "El grupo del usuario es "          . $this->othAuth->user('group_id')    . "BR";

En las vistas usamos el helper oth_auth.php

echo "Páginas de " . $othAuth->user('username') ;

Y así tenemos control de lo que le usuario puede ver y hacer en el programa según su grupo:

if  ($this->othAuth->user('group_id') == 1 )
{
  echo "You can see this because you are admin";
}

Cualquier duda poner un comentario o nos vemos en el IRC: irc.freenode.net#mononeurona.org

Nota: también estoy usando las tablas login_attempts y cake_sessions pues estoy guardando las sesiones en la base de dats en vez de usar /tmp
--- CAKE PHP SESSIONS AND othAuth
CREATE TABLE login_attempts (
id serial PRIMARY KEY,
ip character varying(15) NOT NULL,
num integer DEFAULT 1 NOT NULL,
expire timestamp(0) with time zone DEFAULT now() NOT NULL,
created timestamp(0) with time zone DEFAULT now() NOT NULL
);

CREATE TABLE cake_sessions (
id character varying(255) NOT NULL DEFAULT '' PRIMARY KEY,
data text,
expires integer
);

En necesario indicar que se va a usar la BD para salvar las sesionee en el archivo app/config/core.php.


Última actualización: 2007-06-25 12:02:25-05



ir arriba
The Queen is here Mozilla Firefox The Best DataBase CakePHP Framework CSS GNU Hacker