¿Debo omitir la autorización, con Cancan, de una acción que instanciona un recurso?
-
26-09-2019 - |
Pregunta
Estoy escribiendo una aplicación web para elegir listas aleatorias de tarjetas de conjuntos de tarjetas más grandes y completos. Tengo un modelo de tarjeta y un modelo de conjunto de tarjetas. Ambos modelos tienen un conjunto completo RESTFUL de 7 acciones (: Índice ,: Nuevo ,: Mostrar, etc.). CardSetScontroller tiene una acción adicional para crear conjuntos aleatorios: :random
.
# app/models/card_set.rb
class CardSet < ActiveRecord::Base
belongs_to :creator, :class_name => "User"
has_many :memberships
has_many :cards, :through => :memberships
# app/models/card.rb
class Card < ActiveRecord::Base
belongs_to :creator, :class_name => "User"
has_many :memberships
has_many :card_sets, :through => :memberships
He agregado dispositivos para la autenticación y Cancan para las autorizaciones. Tengo usuarios con un rol de 'editor'. Los editores pueden crear nuevas conjuntos de tarjetas. Los usuarios invitados (usuarios que no han iniciado sesión) solo pueden usar el :index
y :show
comportamiento. Estas autorizaciones funcionan según lo diseñado. Los editores pueden usar actualmente ambos :random
y el :new
acciones sin ningún problema. Los usuarios invitados, como se esperaba, no pueden.
# app/controllers/card_sets_controller.rb
class CardSetsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
load_and_authorize_resource
Quiero permitir que los usuarios invitados usen el :random
acción, pero no el :new
acción. En otras palabras, pueden ver nuevos conjuntos aleatorios, pero no salvarlos. El botón "Guardar" en el :random
La vista de Action está oculta (según lo diseñado) de los usuarios invitados. El problema es que lo primero es el :random
Action DoS es construir una nueva instancia del modelo de conjunto de tarjetas para completar la vista. Cuando Cancan intenta load_and_authorize_resource
Un nuevo conjunto de cartas, lanza una excepción Cancan :: AccessDenied. Por lo tanto, la vista nunca se carga y el usuario invitado recibe un mensaje "necesita iniciar sesión o registrarse antes de continuar".
# app/controllers/card_sets_controllers.rb
def random
@card_set = CardSet.new( :name => "New Set of 10", :set_type => "Set of 10" )
Me doy cuenta de que puedo decir load_and_authorize_resource
para omitir el :random
acción al pasar :except => :random
a la llamada, pero eso se siente "equivocado" por alguna razón.
¿Qué es el "Correcto" forma de hacer esto? ¿Debo crear el nuevo conjunto aleatorio sin instancias de un nuevo conjunto de cartas? ¿Debo seguir adelante y agregar la excepción?
Actualizar
No incluí mi clase de habilidad anterior. Lo he actualizado para incluir la acción ': aleatoria', pero todavía no funciona bien.
class Ability
include CanCan::Ability
def initialize( user )
user ||= User.new # User hasn't logged in
if user.admin?
can :manage, :all if user.admin?
else
# All users, including guests:
can :read, [Card, CardSet]
can :random, CardSet
# All users, except guests:
can :create, [Card, CardSet] unless user.role.nil?
can :update, [Card, CardSet] do |c|
c.try( :creator ) == user || user.editor?
end
if user.editor?
can [:create, :update], [Card, CardSet]
end
end
end
end
Solución
Encontré mi problema. ¡Cancan no fue el problema en absoluto! La siguiente línea en mi controlador de conjunto de tarjetas fue lanzar la excepción y redirigir a mis usuarios de invitado (no iniciar sesión) a la página de inicio de sesión:
before_filter :authenticate_user!, :except => [:show, :index]
Lo cambié para leer:
before_filter :authenticate_user!, :except => [:show, :index, :random]
Y ahora el código funciona según lo previsto: los usuarios invitados pueden ver los nuevos conjuntos aleatorios creados, pero no pueden 'guardarlos' a menos que primero inicien sesión.
Entonces, mi verdadero problema era con Disvise (o, en realidad, mi configuración de disposición) y no con Cancan en absoluto.
Otros consejos
Bueno, lo correcto sería usar la clase de habilidad Cancan para definir las reglas de autorización correctas.
en habilidad.rb
def initialize(user)
#everyone
can [:read, :random], [CardSet]
#everyone who is editor
if user.editor?
can [:new, :create], [CardSet]
etc.
El problema es que lo primero: la acción aleatoria hace es construir una nueva instancia del modelo de conjunto de tarjetas para completar la vista. Cuando Cancan intenta cargar_and_authorize_resource un nuevo conjunto de cartas, lanza una excepción Cancan :: AccessDenied.
Si bien Cancan autoriza la acción del controlador, la construcción de una nueva instancia en acción aleatoria (es decir, CardSet.New) no está en el alcance de Cancan. Probablemente obtenga el error porque no tiene reglas definidas en la habilidad. RB para la acción aleatoria. Mi ejemplo anterior debería resolver su problema