cancancan authorize_resource 没有按预期工作

cancancan authorize_resource not working as expected

对于简单的 cancancan 授权,我遇到了意外行为。

ability.rb

class Ability
  include CanCan::Ability

  def initialize(user)
    # Define abilities for the passed in user here. For example:
    #
    user ||= User.new # guest user (not logged in)
    if user.is_admin?
        can :manage, :all
    elsif user.is_standard?
        can :manage, ServiceOrder, {user_id: user.id}
        can :manage, ServiceOrderDetail, :service_order => { :user_id => user.id }
    end

service_order.rb 控制器(部分显示)

class ServiceOrdersController < ApplicationController
  authorize_resource

  def show
    @service_order = ServiceOrder.includes(:service_order_details).find(params[:id])
  end

end

这不起作用,因为它让控制器显示任何 service_order 记录,而不仅仅是 current_user.

拥有的记录

唯一可行的方法是我手动授权控制器添加:

authorize! :show, @service_order

像这样:

  def show
    @service_order = ServiceOrder.includes(:service_order_details).find(params[:id])
    authorize! :show, @service_order
  end

这没有意义,因为 authorize_resource 应该这样做。

我的建议:使用 authorize_resource 而不是使用 load_and_authorize_resource,下面是您的控制器示例 只需确保您的 strong_parameters 声明:service_order_params

  load_and_authorize_resource param_method: :service_order_params

发生的事情是 authorize_resource 在显示操作之前发生,并且由于 @service_order 尚未设置,它正在检查 class,并且用户确实可以显示 ServiceOrder 刚好受约束。

Adding authorize_resource will install a before_action callback that calls authorize!, passing the resource instance variable if it exists. If the instance variable isn't set (such as in the index action) it will pass in the class name. For example, if we have a ProductsController it will do this before each action.

authorize!(params[:action].to_sym, @product || Product)

from Cancancan documentations

按照 widjajayd 的建议,您需要做的是 load_and_authorize_resource。或者(如果您不想使用 cancancan 默认加载操作)执行 before_filter,在 authorize_resource 调用之前使用您的自定义方法手动加载资源。