如何实现授权?

How to implement authorization?

假设,我有一个名为 Animal 的模型。此模型包含具有两种可能状态的枚举属性。

class Animal < ActiveRecord::Base
  enum kind: [ :cat, :dog ]
end

然后在我的控制器中创建不同的实例变量。

class AnimalsController < ApplicationController
  def index
    @cats = Animal.cat
    @dogs = Animal.dog
  end
end

在我看来,我得到了两个独立的集合。

<h1>Animals</h1>

<%= render partial: 'animals/cat', collection: @cats, as: :cat %>
<%= render partial: 'animals/dog', collection: @dogs, as: :dog %>

如何才能授权能够编辑第一个集合的资源而不能编辑第二个?

以下方法行不通,因为它完全只对一个动作有效。

before_action :current_user_only, except: [:edit]

那么,我该如何实现这种授权呢?

提前致谢!

授权 - 以任何身份 - 通常由两种模式表示:

  • record/object 基于
  • role/user 基于

您似乎需要的是基于 record/object 的授权;如果对象符合特定条件,则用户可以编辑该对象。

在 Rails 中执行此操作的最有效方法是使用名为 Pundit, although I prefer CanCanCan (originally CanCan 的 gem):

#Gemfile 
gem "pundit"

#app/policies/animal.rb
class AnimalPolicy
  attr_reader :user, :animal

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

  def edit?
    animal.cat?
  end

  def update?
    animal.cat?
  end
end

#app/controllers/animals_controller.rb
class AnimalsController < ApplicationController
   def edit
      @animal = Animal.find params[:id]
      authorize @animal
   end

   def update
      @animal = Animal.find params[:id]
      authorize @animal
   end
end

然后您可以在 front-end:

上验证
<% if policy(animal).update? %>
   <%= link_to "Edit", animal %>
<% end %>

--

这使您能够允许用户执行您认为合适的任何操作。


更新

由于您希望评估用户和对象,您很幸运 PunditCanCanCan 默认都支持 users:

#app/policies/animal.rb
class AnimalPolicy
  attr_reader :user, :animal

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

  def edit?
    user.moderator? && animal.cat?
  end

  def update?
    user.moderator? && animal.cat?
  end
end

要记住的最后一点是授权是一个布尔模式 - unless true deny access。这意味着您只需在授权系统中(如上所述)向 return truefalse.

提供条件逻辑