什么是限制与权威人士对Rails的整个控制器的干法?

问题描述 投票:2回答:3

我使用Pundit与Rails和我有一个控制器,我需要完全从一个特定的用户角色限制。我的角色是“员工”和“消费者”。工作人员应该有充分的访问控制,但消费者应该都进不去。

有没有办法做到这一点比限制每一个动作一个接一个更干?

举例来说,这里是我的政策:

class MaterialPolicy < ApplicationPolicy
  attr_reader :user, :material

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

  def index?
    user.staff?
  end

  def show?
    index?
  end

  def new?
    index?
  end

  def edit?
    index?
  end

  def create?
    index?
  end

  def update?
    create?
  end

  def destroy?
    update?
  end
end

而我的控制器:

class MaterialsController < ApplicationController
  before_action :set_material, only: [:show, :edit, :update, :destroy]

  # GET /materials
  def index
    @materials = Material.all
    authorize @materials
  end

  # GET /materials/1
  def show
    authorize @material
  end

  # GET /materials/new
  def new
    @material = Material.new
    authorize @material
  end

  # GET /materials/1/edit
  def edit
    authorize @material
  end

  # POST /materials
  def create
    @material = Material.new(material_params)
    authorize @material

    respond_to do |format|
      if @material.save
        format.html { redirect_to @material, notice: 'Material was successfully created.' }
      else
        format.html { render :new }
      end
    end
  end

  # PATCH/PUT /materials/1
  def update
    authorize @material
    respond_to do |format|
      if @material.update(material_params)
        format.html { redirect_to @material, notice: 'Material was successfully updated.' }
      else
        format.html { render :edit }
      end
    end
  end

  # DELETE /materials/1
  def destroy
    authorize @material
    @material.destroy
    respond_to do |format|
      format.html { redirect_to materials_url, notice: 'Material was successfully destroyed.' }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_material
      @material = Material.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def material_params
      params.require(:material).permit(:name)
    end
end

有没有办法做到这一点,我不理解,或者是权威人士是怎么设计的,要求你要明确?

ruby-on-rails ruby authorization pundit
3个回答
3
投票

第一步就是移动电话授权给您的回调:

def set_material
  @material = Material.find(params[:id])
  authorize @material
end

你也可以写@material = authorize Material.find(params[:id])如果你的权威人士版本是最新的(以前的版本返回真/假而不是记录)。

权威人士具有的灵活性,你选择如何使用它,数额巨大。例如,您可以创建一个separate headless policy

class StaffPolicy < ApplicationPolicy
  # the second argument is just a symbol (:staff) and is not actually used
  def initialize(user, symbol)
    @user = user
  end
  def access?
    user.staff?
  end
end

然后用这个在回调授权整个控制器:

class MaterialsController < ApplicationController
  before_action :authorize_staff
  # ...

  def authorize_staff
    authorize :staff, :access?
  end
end

或者,你可以使用继承或混入擦干你的策略类:

class StaffPolicy < ApplicationPolicy
  %i[ show? index? new? create? edit? update? delete? ].each do |name|
    define_method name do
      user.staff?
    end
  end
end

class MaterialPolicy < StaffPolicy
  # this is how you would add additional restraints in a subclass
  def show?
    super && some_other_condition
  end
end

权威人士一切只不过是普通的老红宝石OOP之后。


1
投票

权威人士并不需要你要明确,但它允许它。如果在你的政策index?方法不重复,你想明确的能力。

你可以通过看一些移动授权检查到set_material方法的开始,即在检查中减少了一半下来。

另一半可以抽象到其他私有方法,如果你想要的,但我觉得他们很好原样。

您还可以看看添加一个before_action回调调用基于动作的名称授权,你通过你的其他的回调memoized @material后,但是可读性可能受到影响。


0
投票

使用的方法authorize第二个参数。例如:

authorize @material, :index?

现在,您可以删除所有只是调用index?其他方法

© www.soinside.com 2019 - 2024. All rights reserved.