【问题标题】:How do I restrict authorization to a user's resource index action using Pundit? I don't think the answer is scope如何使用 Pundit 限制对用户资源索引操作的授权?我不认为答案是范围
【发布时间】:2016-12-08 18:44:22
【问题描述】:

在使用 Pundit 时,我正在努力授权嵌套资源的索引操作。 Pundit 如此狡猾且可能很容易,我讨厌不得不将其抛在一边,因为我无法弄清楚这一点。我想一旦我理解了这部分,其他一切都会顺理成章。我已经阅读了很多人的帖子,他们提出的问题与我所问的问题非常相似,似乎最接近我所问问题的帖子永远不会得到解决。所以,我还在寻找答案。

class User < ApplicationRecord
  enum role: [:user, :admin]
  after_initialization :set_default_role, :if => :new_record?
  def set_default_role
  self.role ||= :user
  has_many :galleries, dependent: :destroy
end

class Gallery < ApplicationRecord
  belongs_to :user
  validates :user_id, presence: true
  validates :title,, presence: true
end

我已经通过 UserPolicy 设置了我想要的用户。它没有从 ApplicationPolicy 继承,因为我正在查看的教程说我不需要它。

我的路线如下所示:

devise_for :users, path: 'accounts
resources :users, shallow: true do
  resources :galleries
end

基本上我不希望一个用户看到另一个用户的东西,即索引、显示......操作。我相信这被称为封闭系统。我查看用户图库(我的嵌套资源)索引的路径如下所示:

localhost:/users/20/galleries

我不希望用户 19 看到用户 20 在其图库索引中的内容。我该怎么做?

这就是我的 GalleryController 的样子:

before_action :authenticate_user! #I'm using devise
def index
  @galleries = current_user.galleries.all
  #authorize ????? <<part of what I don't understand
end

private
def gallery_params
  params.require(:gallery).permit(:title)
end

我真的不知道我应该在 GalleryPolicy 中为索引做什么。我已经制定了显示操作,因为它只是根据用户 ID 的实例检查画廊的实例。这是 GalleryPolicy

attr_reader :user, :model

def initialize(user, model)
  @user = user
  @gallery = gallery
end

def show?
  @gallery.user_id == user.id
end

def index?
  # I can't figure it out
end

def new?
  #actually this is confusing too
end

【问题讨论】:

    标签: ruby-on-rails nested authorization ruby-on-rails-5 pundit


    【解决方案1】:

    首先,我一直编写从 ApplicationPolicy 继承的 Pundit 策略,所以让我们从那里开始。 ApplicationPolicy 使用用户和记录进行初始化。该记录将是您希望用户有权查看的模型。在这种情况下,一个画廊。

    其次,每个策略都应该包含一个范围。这也在 ApplicationPolicy 内部初始化,但您的工作是根据需要限制范围。

    class GalleryPolicy < ApplicationPolicy
      class Scope < Scope
        def resolve
          scope.where(:user_id => user.id)
        end
      end
    
      # no need for an index? method here. we will see this in the controller
    
      # essentially here we are checking that the user associated to the record
      # is the same as the current user
      def show?
        record.user == user
      end
    
      # this is actually already the case in ApplicationPolicy but I added 
      # it here for clarity
      def new?
        create? 
      end
    
      # who do we want to be able to create a gallery? anyone!
      # so this simple returns true
      def create?
        true
      end
    end
    

    然后在您的 GalleryController 中,您将每次都对模型进行授权。我们现在将看到,只有 index 操作有点不同:

    # controllers/gallery_controller.rb
    def index 
     @galleries = policy_scope(Gallery)
     # as we specified the scope in GalleryPolicy to only include galleries which belong 
     # to the current user this is all we need here!
    end
    
    # your other actions will look something like this:
    def show
      @gallery = Gallery.find(params[:gallery_id]
      authorize @gallery
    end
    
    def new
      @gallery = Gallery.new # or @gallery = current_user.galleries.build
      authorize @gallery
    end
    
    [...]
    

    我希望这会有所帮助!一旦你掌握了 Pundit,它就是一个非常棒的工具。

    【讨论】:

    • 感谢您的评论。我按照您所说的执行了所有操作,但并没有改变情况。第一:用户A 仍然能够看到用户B 的画廊索引。第二:每个用户的画廊索引上都有其他用户的画廊。如果用户尝试访问用户 B 的图库索引页面,我想将用户 A 重定向到其他页面,并显示“拒绝访问”的闪存消息。而且我不希望任何其他用户的画廊出现在另一个用户的画廊索引中。
    • 其实我觉得你是对的。我现在遇到的问题是相关的,但不是我要求帮助解决的问题。这行得通。谢谢!
    • 很高兴我能帮上忙!如果您针对新问题发布另一个问题,请在此处将链接发送给我,我会查看它是否可以提供帮助:)
    • 这里有一些额外的想法:stackoverflow.com/a/33306150/1611925
    猜你喜欢
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多