Pundit::PolicyScopingNotPerformedError

2019-06-27 04:44发布

问题:

I am fairly new to using this Pundit gem but seem to be having trouble understanding the policy system. From everything I have read it all appears to be correct though I am still getting an error

Application Controller

class ApplicationController < ActionController::Base
  include Pundit
  protect_from_forgery
  before_filter :authenticate_person!

  # Verify that controller actions are authorized. Optional, but good.
  after_filter :verify_authorized,  except: :index
  after_filter :verify_policy_scoped, only: :index


  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  private

  def pundit_user
    Person.find_by_id(current_person)
  end

  def user_not_authorized
    flash[:alert] = "You are not authorized to perform this action."
    # redirect_to(request.referrer || root_path)
  end
end

Application Policy

class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    raise Pundit::NotAuthorizedError, "must be logged in" unless user
    @user = user
    @record = record
  end

  def index?
    false
  end

  def show?
    scope.where(:id => record.id).exists?
  end

  def create?
    false
  end

  def new?
    create?
  end

  def update?
    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

  def scope
    Pundit.policy_scope!(user, record.class)
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      scope
    end
  end
end

Error Message

Pundit::AuthorizationNotPerformedError in Devise::SessionsController#new

回答1:

You probably need to check this section from Pundit's readme.

It basically says, that when using verify_authorized is used in after_action, it will check if authorized was actually called.

Pundit adds a method called verify_authorized to your controllers. This method will raise an exception if authorize has not yet been called. You should run this method in an after_action to ensure that you haven't forgotten to authorize the action.

The same is true for verify_policy_scoped, but for policy_scope:

Likewise, Pundit also adds verify_policy_scoped to your controller. This will raise an exception in the vein of verify_authorized. However, it tracks if policy_scope is used instead of authorize. This is mostly useful for controller actions like index which find collections with a scope and don't authorize individual instances.

In your case exception is caused by the fact that you didn't called authorize in Devise::SessionsController#new action.

I think, the best way to deal with it, is to remove after_action checks from ApplicationController and move them to a subclass.



回答2:

The answer to this is to check if it's a devise controller.

after_action :verify_authorized, :except => :index, unless: :devise_controller?

From: https://github.com/elabs/pundit/issues/113 and https://gorails.com/forum/using-pundit-with-activeadmin