Sollte ich die Autorisierung mit Cancan über eine Maßnahme überspringen, die eine Ressource instanziiert?

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

  •  26-09-2019
  •  | 
  •  

Frage

Ich schreibe eine Web -App, um zufällige Kartenlisten aus größeren, vollständigen Kartensätzen auszuwählen. Ich habe ein Kartenmodell und ein Kartenset -Modell. Beide Modelle haben einen vollständigen Satz von 7 Aktionen (: Index,: neu,: show usw.). Der CardsetsController hat eine zusätzliche Aktion zum Erstellen von zufälligen Sätzen: :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

Ich habe Devise für Authentifizierung und Cancan für Autorisierungen hinzugefügt. Ich habe Benutzer mit einer "Editor" -Rolle. Die Redakteure dürfen neue Kartensätze erstellen. Gastbenutzer (Benutzer, die sich nicht angemeldet haben) können nur die verwenden :index und :show Aktionen. Diese Genehmigungen arbeiten wie entworfen. Redakteure können derzeit beide verwenden :random und die :new Handlungen ohne Probleme. Wie erwartet können Gastbenutzer nicht.

# app/controllers/card_sets_controller.rb
class CardSetsController < ApplicationController
  before_filter :authenticate_user!, :except => [:show, :index]
  load_and_authorize_resource

Ich möchte den Gastnutzern erlauben, die zu verwenden :random Aktion, aber nicht die :new Aktion. Mit anderen Worten, sie können neue zufällige Sets sehen, sie aber nicht retten. Die Schaltfläche "Speichern" auf der :random Die Ansicht von Action ist vor den Gastnutzern versteckt (wie entworfen). Das Problem ist, das erste, was das ist :random Aktion erstellt eine neue Instanz des Kartenset -Modells, um die Ansicht auszufüllen. Wenn Cancan versucht zu load_and_authorize_resource Ein neues Kartenset, das eine Ausnahme von Cancan :: AccessDenied ausgelöst hat. Daher wird der Ansicht nie geladen und dem Gastbenutzer wird eine Nachricht "Sie müssen sich anmelden oder anmelden" bedient.

# app/controllers/card_sets_controllers.rb
def random
  @card_set = CardSet.new( :name => "New Set of 10", :set_type => "Set of 10" )

Mir ist klar, dass ich es sagen kann load_and_authorize_resource um das zu überspringen :random Aktion durch Passieren :except => :random zum Anruf, aber das fühlt sich einfach an "falsch" aus irgendeinem Grund.

Was ist das "Rechts" Weg, dies zu tun? Sollte ich den neuen zufälligen Satz erstellen, ohne einen neuen Kartenset zu instanziieren? Soll ich die Ausnahme hinzufügen?

Aktualisieren

Ich habe meinen Fähigkeitsklassen oben nicht hinzugefügt. Ich habe es aktualisiert, um die Aktion von ': Random' einzuschließen, aber es funktioniert immer noch nicht ganz richtig.

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
War es hilfreich?

Lösung

Ich fand mein Problem. Cancan war überhaupt nicht das Problem! Die folgende Zeile in meinem Cardset -Controller war die Ausnahme und habe meinen Gast (nicht angemeldete) Benutzer zur Anmeldung auf Seite umleiten:

before_filter :authenticate_user!, :except => [:show, :index]

Ich habe es geändert, um zu lesen:

before_filter :authenticate_user!, :except => [:show, :index, :random]

Und jetzt funktioniert der Code wie beabsichtigt: Gastbenutzer können die neuen zufälligen Sets anzeigen, können sie jedoch nicht "speichern", es sei denn, sie melden sich zuerst an.

Mein eigentliches Problem war also mit Devise (oder eigentlich meine Devise -Konfiguration) und überhaupt nicht mit Cancan.

Andere Tipps

Das Richtige wäre, die Cancan -Fähigkeitsklasse zu verwenden, um die richtigen Autorisierungsregeln zu definieren.

in Fähigkeit.RB

  def initialize(user)
#everyone
    can [:read, :random], [CardSet]
#everyone who is editor
    if user.editor?
      can [:new, :create], [CardSet]

etc

Das Problem ist, dass die: zufällige Aktion als erstes eine neue Instanz des Kartenset -Modells erstellt, um die Ansicht auszufüllen. Wenn Cancan versucht, einen neuen Kartenset zu laden_and_authorize_resource, wird eine Ausnahme von Cancan :: AccessDenied ausgelöst.

Während Cancan die Controller -Aktion autorisiert, befindet sich eine neue Instanz in zufälliger Aktion (dh CardSet.NEW) nicht im Rahmen von Cancan. Sie erhalten wahrscheinlich den Fehler, da Sie in der Fähigkeit. RB für zufällige Aktionen keine Regeln definiert haben. Mein obiger Beispiel sollte Ihr Problem lösen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top