Roles y usuarios con Devise y CanCan

cc6Manejar usuarios y roles de forma básica en una aplicación RoR resulta un poco sencillo al utilizar gemas como Devise y CanCan que se complementan una con la otra y nos proporcionan un mecanismo tanto para autentificar a los usuarios como para comprobar si tienen autorización para realizar alguna acción en nuestra aplicación.

Para este ejemplo se está considerado que ya se ha instalado Devise con su configuración básica que se encuentra en su documentación oficial https://github.com/plataformatec/devise: el modelo User sin ningún campo adicional, no se ha creado aún un controlador para administrar lo usuarios.

CanCan

 

Para su adopción tomamos como base la información proporcionada por CanCan gem  https://github.com/ryanb/cancan de donde se ha considerado la idea de asignar sólo un rol a cada usuario, para ello en la información nos indica que:

  • Debemos crear un nuevo atributo string al modelo User
  • Asignar los permisos según el rol establecido para el usuario (Defining Abilities)
  • Comprobar los permisos en Vistas y Controladores

Suponiendo que Devise está operando correctamente y ya hemos creado algún usuario, procedemos con la instalación.

Instalación de CanCan

Se agrego gem “cancan” en el Gemfile

Se ejecutó el comando

$ rails g cancan:ability

Esto creó la clase Ability en /models, para asignar los permiso que tendrá cada rol sobre los modelos de nuestra aplicación consideremos dar una lectura a la especificación técnica sobre la definicion de abilitiies en https://github.com/ryanb/cancan/wiki/defining-abilities

El código que he agregado a este ejemplo:

class Ability
 include CanCan::Ability
def initialize(user)
 user ||= User.new
 if user.role == "manager"
   can :manage, :all
 elsif user.role == "seller"
   alias_action :create, :read, :update, :to => :cru
   can :cru, Sale
   can :cru, SaleDetail
   can :cru, Client
  end
 end
end

Para este caso, se está indicando que el usuario con el rol manager tiene acceso a todo, mientras que el usuario que tiene el rol seller, sólo puede operar en Sale, SaleDetail y Cliente para registrar nuevo, leer y actualizar, pero sobre estos modelos no podrá eliminar.

Modificación del modelo

CanCan indica como debe realizarse la modificación del modelo a modo de como se define la autorización basada en roles, la información está disponible en https://github.com/ryanb/cancan/wiki/Role-Based-Authorization

Para este ejemplo se consideró la sección: One role per user

En esta se indica que debe agregarse el atributo role al modelo, para ello debe generarse una migración:

$ rails generate migration add_role_to_users role:string

En mi caso, quiero que cada nuevo usuario se le asigne por default el rol seller, para esto he modificado la migración antes de ejecutarla:

class AddRoleToUsers < ActiveRecord::Migration
 def change
  add_column :users, :role, :string, default: "seller"
 end
end

Se realizó la migración

$ rake db:migrate

Comprobando Abilities y Authorization

Realizado este procedimiento, se procedió con lo indicado en la sección 2 y 3 de https://github.com/ryanb/cancan

Para autorizar automáticamente las acciones permitidas en un controlador para el usuario autentificado, se agregó en cada controlador:

load_and_authorize_resource

Ejemplo para mi controlador ClientsController…

class ClientsController < ApplicationController
 load_and_authorize_resource
before_action :set_client, only: [:show, :edit, :update, :destroy]

Si la autorización falla, dice CanCan, deberá controlarse la excepción y redireccionar a la entrada principal de la aplicación adicionando a ello el mensaje de la excepción, para esto indica modificar el controlador principal de la aplicación: ApplicationController agregando (antes de protected) :

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

 

Modificación de las vistas

En este ejemplo básico solo se modificó la vista Index de Clients y Sales para comprobar si el usuario puede eliminar, entonces se le muestra el link:

 <% if can? :destroy, client %>
   <%= link_to t('.destroy', :default => t("helpers.links.destroy")),
   client_path(client),
   :method => :delete,
   :data => { :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sur   e?')) },
   :class => 'btn btn-mini btn-danger' %>
 <% end %>

Modificación de usuarios ya registrados

Como nuestros usuarios existentes no tiene un rol asignado y no contamos aún con el controlador para administrar usuarios, entonces lo hacemos desde la consola de Rails.

$ rails c
> user = User.find(1)
> user.role = "seller"
> user.save

Actualizado el usuario, ejecutamos el servidor y cerramos la sesión del usuario(si la sesión está iniciada).

Al ingresar a la aplicación comprobamos que no se muestra la opción Eliminar

cc4

 

 

 

 

 

 

 

 

 

Mientras que en la vista que no se editó, se muestra normalmente.

cc5

 

 

 

 

 

 

 

 

Y además, al intentar eliminar en este caso un producto, y el usuario no tiene privilegios sobre el modelo Producto (ver la clase Ability), por default nos muestra el mensaje de error y nos ha redireccionado al punto de entrada principal de la aplicación.

cc6

 

 

 

 

 

 

Por lo tanto, siguiendo la información especificada por estas gemas, podemos obtener como resultado una aplicación funcional, en este caso, se han agregado roles y usuarios a nuestra aplicación demos disponible en https://github.com/afelipelc/DemoRailsVentas/

;D

Anuncios

Escribe tu comentario:

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s