Ruby on Rails
Autorización con CanCan
Buscar..
Introducción
CanCan es una estrategia de autorización simple para Rails que se desacopla de los roles de usuario. Todos los permisos se almacenan en una sola ubicación.
Observaciones
Antes de usar CanCan, no olvide crear Usuarios por gema o manualmente. Para obtener la máxima funcionalidad de CanCan puede crear un usuario administrador.
Empezando con CanCan
CanCan es una popular biblioteca de autorizaciones para Ruby on Rails que restringe el acceso de los usuarios a recursos específicos. La última gema (CanCanCan) es una continuación del proyecto muerto CanCan .
Los permisos se definen en la clase de Ability
y se pueden usar desde controladores, vistas, ayudantes o cualquier otro lugar en el código.
Para agregar soporte de autorización a una aplicación, agregue la gema CanCanCan al Gemfile
:
gem 'cancancan'
Luego define la clase de habilidad:
# app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
end
end
Luego, verifique la autorización usando load_and_authorize_resource
para cargar modelos autorizados en el controlador:
class ArticlesController < ApplicationController
load_and_authorize_resource
def show
# @article is already loaded and authorized
end
end
authorize!
para comprobar la autorización o plantear una excepción
def show
@article = Article.find(params[:id])
authorize! :read, @article
end
can?
para verificar si un objeto está autorizado contra una acción particular en cualquier lugar en los controladores, vistas o ayudantes
<% if can? :update, @article %>
<%= link_to "Edit", edit_article_path(@article) %>
<% end %>
Nota: Esto supone que el usuario current_user
es proporcionado por el método current_user
.
Definiendo habilidades
Las habilidades se definen en la clase Ability
utilizando los métodos de can
y la cannot
. Considere el siguiente ejemplo comentado para referencia básica:
class Ability
include CanCan::Ability
def initialize(user)
# for any visitor or user
can :read, Article
if user
if user.admin?
# admins can do any action on any model or action
can :manage, :all
else
# regular users can read all content
can :read, :all
# and edit, update and destroy their own user only
can [:edit, :destroy], User, id: user_id
# but cannot read hidden articles
cannot :read, Article, hidden: true
end
else
# only unlogged visitors can visit a sign_up page:
can :read, :sign_up
end
end
end
Manejando gran cantidad de habilidades.
Una vez que el número de definiciones de habilidades comienza a crecer en número, se vuelve cada vez más difícil manejar el archivo de Habilidad.
La primera estrategia para manejar estos problemas es mover las habilidades a métodos significativos, según este ejemplo:
class Ability
include CanCan::Ability
def initialize(user)
anyone_abilities
if user
if user.admin?
admin_abilities
else
authenticated_abilities
end
else
guest_abilities
end
end
private
def anyone_abilities
# define abilities for everyone, both logged users and visitors
end
def guest_abilities
# define abilities for visitors only
end
def authenticated_abilities
# define abilities for logged users only
end
def admin_abilities
# define abilities for admins only
end
end
Una vez que esta clase crezca lo suficiente, puede intentar dividirla en diferentes clases para manejar las diferentes responsabilidades de esta manera:
# app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
self.merge Abilities::Everyone.new(user)
if user
if user.admin?
self.merge Abilities::Admin.new(user)
else
self.merge Abilities::Authenticated.new(user)
end
else
self.merge Abilities::Guest.new(user)
end
end
end
y luego definir esas clases como:
# app/models/abilities/guest.rb
module Abilities
class Guest
include CanCan::Ability
def initialize(user)
# Abilities for anonymous visitors only
end
end
end
y así sucesivamente con Abilities::Authenticated
, Abilities::Admin
o cualquier otro.
Prueba rápidamente una habilidad
Si desea probar rápidamente si una clase de habilidad está dando los permisos correctos, puede inicializar una habilidad en la consola o en otro contexto con el entorno de rieles cargados, solo pase una instancia de usuario para probar:
test_ability = Ability.new(User.first)
test_ability.can?(:show, Post) #=> true
other_ability = Ability.new(RestrictedUser.first)
other_ability.cannot?(:show, Post) #=> true
Más información: https://github.com/ryanb/cancan/wiki/Testing-Abilities