Autorización en Rails 3: CanCan y Rolify [QuickTut]


Introducción

Para ciertas aplicaciones web, (sobretodo aquellas dispuestas para el nivel empresarial) requerimos no solo de la capacidad para Autenticar usuarios (registrarlos y darles acceso a cierto contenido si se han logueado) sino que también necesitamos Autorizarles a hacer cosas. Tal como en un sistema Linux (por dar un ejemplo) tenemos diferentes grupos de usuarios y diferentes tipos de usuarios, en una aplicación web también. En el ejemplo de Linux/Unix que cito, cada usuario según los grupos a los que pertenezca o los permisos que tenga podrá manipular y/o gestionar distintas partes del sistema, mientras que otras se mantendrán restringidas a usuarios de más rango. Así mismo, tenemos un superusuario (que bien conocerán los linuxeros y maqueros como root) el cual puede hacer prácticamente todo en un sistema sin obstrucciones. Esta misma lógica y jerarquía aplica cuando creamos una aplicación web, y aunque aquí tenemos que preocuparnos por menos asociaciones y roles que en un Sistema Operativo, el principio teórico básico es el mismo.

La autenticación, ha sido por mucho tiempo la parte más compleja (o bueno, una de las más complejas) para programar en la mayoría de aplicaciones web que la requieren, debido a la lógica y esfuerzo que hay detrás. Sin embargo, una vez que entiendes cómo funciona y cómo se hace, todo se vuelve más sencillo y el concepto es prácticamente el mismo para cualquier caso en que la ocupemos. Todo es cosa de sobrevivir a la curva de aprendizaje que representa... Veamos pues, cómo autorizar usuarios:

NOTAS: Para poder seguir este tutorial, debes de haber seguido con antelación el tutorial express de ruby on rails que hicimos y también el de autenticación, de manera que tengas los conocimientos apropiados para trabajar en este tutorial, la aplicación de ejemplo que usaré aquí será el blog construido en el tutorial express con las técnicas de autenticación del tutorial de sorcery aplicadas, aunque cualquier aplicación que ya disponga de un mecanismo de autenticación nos servirá. A lo largo de la serie de tutoriales sobre Rails que hemos escrito aquí, se ha buscado el mantener las cosas simples de manera que todos las entiendan, sin embargo, contrario con otros sitios, nosotros siempre buscamos que lo aprendido aquí tenga aplicación práctica una vez terminado el tutorial. Lo mismo será con este tutorial de autorización, donde aprenderemos los principios básicos de éste tema de una manera simple pero con un escenario que puede resultar cercano a algún desafío de la vida real. 

Aplicación práctica

Supongamos que yo tengo un blog donde ya autentico usuarios, pero entonces todo aquel que está autenticado tiene capacidades para añadir, editar y borrar posts entre otras cosas, cosas que sólo deberían permitírsele al administrador. Si bien podríamos ocultar los enlaces y las rutas a únicamente los administradores o bien, hacer HTTP Basic Authentication sobre los enlaces, estos no son enfoques correctos si tarde que temprano queremos crear una aplicación de talla empresarial, tarde que temprano tendremos que hacer autorización real y es mejor que lo aprendamos ahora a que lo hagamos más tarde. Lo primero que haremos entonces será añadir las gemas CanCan y Rolify a nuestro Gemfile con las siguientes líneas:

gem "cancan"
gem "rolify"

Luego corremos (estando posicionados con la terminal dentro del directorio de la aplicación) bundle install y más tarde, Haremos un archivo de habilidades que se guardará en app/models/ability.rb con el siguiente comando:

rails generate cancan:ability

Este archivo deberá llevar el siguiente código dentro:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.has_role? :admin
      can :manage, :all
    end
  end
end

Y básicamente, el archivo lo que define es que, Si el usuario es ADMINISTRADOR entonces tiene derecho de manipular las acciones protegidas por cancan (métodos del controlador deseado como veremos más adelante); De otra forma se le considera no administrador. Para entender mejor cómo se tiene que describir este archivo según nuestras necesidades, vayan a la página oficial del proyecto o vean este railscast.

Pero, ¿Qué pasa si no es administrador? bueno, en ese caso, se suelta una excepción que debe ser manejada por CanCan (Generalmente lo que haremos será mostrar un mensaje de "No está autorizado") y para esto, (Más o menos como cuando definimos el método privado para el manejo de excepción en sorcery) añadiremos las siguientes líneas a nuestro app/controllers/application_controller.rb:

rescue_from CanCan::AccessDenied do |exception|
   redirect_to root_path, :alert => exception.message
 end

Igual, la manera de redactar la orden/órdenes mediante las que CanCan manejará las excepciones y cómo modificar los mensajes de alerta se encuentra detallada en la página del proyecto... En mi caso (usando el ejemplo del blog que hemos estado manejando desde el tutorial rails express) el application_controller queda así:

Click para Agrandar

Una vez guardados nuestros cambios, generamos los roles de usuario con este comando:

rails generate rolify:role

Y esto nos generará varios archivos, uno de los cuales encontraremos en app/models/role.rb y contendrá el siguiente código:

class Role < ActiveRecord::Base
  has_and_belongs_to_many :users, :join_table => :users_roles
  belongs_to :resource, :polymorphic => true
end

Que en términos que nos interesan, definirá que un rol puede pertenecer a varios usuarios en la forma de una asociación polimórfica. Más información de todo eso y cómo generar los archivos de configuración de roles en la página oficial de Rolify.

Luego de esto, tenemos que correr bundle exec rake db:migrate para hacer válidas las bases de datos y luego editaremos nuestro controlador del recurso que queremos gestionar con autorización para habilitar la gestión con CanCan; Con fines de lograr esto, le añadiremos 1 sola línea a dicho controlador, que es esta:

load_and_authorize_resource :only => [:new, :edit, :destroy]

(En el caso del ejemplo del blog y su controlador posts) Ustedes, según su aplicación, elegirían las acciones o acción que quieran proteger con autorización, si es una sola, solo escriben :only => :acción luego de load_and_authorize_resource, si son todas , solo escribiríamos load_and_authorize_resource y si son varias, las ponen en array como ahí arriba. En nuestro ejemplo, como protegeremos la habilidad de manipular posts, nuestro controlador de posts lleva esa línea  de arriba y queda así:


Click para agrandar

Acto seguido debemos crear un usuario administrador. En otros tutoriales les enseñarían que pueden añadir casillas de verificación donde todos los usuarios pueden escoger sus propios roles al registrarse, pero esto no lo harías en la vida real. En la vida real, en una aplicación para una empresa, dejarías que la gente creara sus usuarios normalmente por medio de tu sistema de autenticación y luego volverías administrador a los que requieras que lo sean mediante la interfaz de ActiveRecord. Eso es lo que haremos aquí:

So, Juan Pérez se registra con el nombre de usuario Juanp y decides que debe ser administrador, muy bien. Lo primero que haces es correr la consola rails desde tu terminal (estando dentro de la carpeta de tu proyecto) con rails c y luego lo vuelves administrador de la siguiente manera:

User.all
User.find(id).add_role(:admin)

Esto es ActiveRecord como explicamos en el primer tutorial de Rails que hicimos y lo que hicimos aquí fue primero listar todos los usuarios para saber el id de JuanP, luego usamos Find (Con el ID del usuario de JuanP en lugar de la palabra id dentro de los paréntesis) para tomarlo y añadirle el rol de administrador con el método de add_role y el símbolo :admin que definimos al hacer nuestro archivo de role.rb hace unos pasos atrás. Ya terminamos aquí, salte de la consola rails con Ctrl + D.

Ahora haz otro usuario cualquiera desde la interfaz de tu servidor (inícialo primero con rails s), pero no le des privilegios de administrador. Haz login con ese usuario y trata de añadir o borrar, o editar un post (Si estás siguiendo esto con nuestro blog de ejemplo claro está). Se te regresará a la página principal y verás un mensaje como este en la parte de arriba:

Click para Agrandar


Ahora, accede como Juan Pérez (o bien el usuario que hayas vuelto administrador) y trata de editar, borrar o crear posts, Verás que sí puedes. Esto se debe a que declaramos a ese usuario administrador en nuestra base de datos con ActiveRecord. Básicamente de eso se trata la autorización, y gracias a CanCan y Rolify lo hemos logrado de una manera bastante sencilla! (Cuando generalmente cuesta mucho trabajo). Obvio aquí solo definimos 1 Rol de administrador, pero puedes poner más según ocupes, es cosa de hacer pequeños Tweaks al código. Checa las páginas oficiales de CanCan y Rolify para mejorar tus conocimientos y también este video si quieres aprender mejor cómo manejar roles y demás.