¿Debo omitir la autorización, con Cancan, de una acción que instanciona un recurso?

StackOverflow https://stackoverflow.com/questions/2831720

  •  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
¿Fue útil?

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top