【问题标题】:How does cancancan set the model instance, and how can I inspect it?cancancan 如何设置模型实例,如何检查它?
【发布时间】:2021-01-29 13:58:06
【问题描述】:

我注意到用户可以访问他们不应该访问的操作。

我在 Rails 控制台中 debugged 使用类似的东西

user = User.first 
physician = Physician.first 
ability = Ability.new(user)
ability.can?(:send_message, physician)
# => false

上面说用户不能访问该医生的 send_message 操作,这是期望的行为,但我知道他们可以在应用程序中!

认为这缩小了cancancan由于某种原因加载错误模型实例的问题的原因。 cancan 文档中也暗示了这一点:

注意:这假设模型实例正在正确加载。

但问题是我不确定如何从这里诊断问题,因为控制台说它应该可以工作。不知道怎么查看cancancan设置的模型实例,也不知道还有什么办法。

有什么想法吗?

更新

我确实设法通过在控制器中使用 authorize! :send_message, physician 来解决这个问题,但是因为我只是偶然发现了这种行为,我认为找出错误模型的原因更为重要正在加载实例(尤其是这样我可以查看其他地方是否也发生了这种情况)。

我知道为什么它可能会发生(但我仍然不知道如何诊断它)

我认为发生这种情况是因为我有许多自定义操作,其中一些有 @physician = Physician.find(current_user.physician.id)(即他们是当前用户),而另一些则更像 @physician = Physician.find_by_id(physician_params[:id])。我不确定 cancan 如何设置实例模型,但我知道它不是通灵的,所以它不知道是将其设置为当前用户的医生实例,还是传入的医生 ID 的医生实例。

还剩下什么?

cancancan 如何为自定义方法设置模型实例(我认为它会尝试某些方法,如果不起作用,请尝试其他方法等)?

有帮助的小笔记:

  • load_and_authorize_resource 确实尝试为 non RESTful actions 加载模型实例
  • docs 中的一些有用信息
  • This 可能与我的经历有关:

当我返回 slug 时,它会破坏这种行为,我可以编辑所有口袋妖怪。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-6 cancan cancancan


    【解决方案1】:

    把我的笔记留在这里,以防它们对其他人有帮助。

    TL;DR,cancancan 提出了 很多 细微的假设,而您从一开始就不会知道这些假设。我通过彻底阅读康康康乐曲readmecodedefining abilities docs中的cmets发现了其中的许多@

    所以就这样吧..

    cancancan 的工作原理

    • 如果您在控制器操作本身中调用authorize!,cancancan 将在每个控制器操作中查找实例变量。
    • 如果您只是在控制器的开头添加load_and_authorize_resource,则do two things
      1. 加载一个cancancan认为应该加载的实例变量,并且
      2. 检查该模型实例的授权
    • 请注意,对于自定义操作,load_and_authorize_resource 仍会尝试加载模型实例,但它如何知道要加载什么?它没有,它猜测,对我来说,我不喜欢,所以要注意这一点。
      • 对我来说,我更喜欢自己分两个步骤完成load_and_authorize_resource 的工作,所以我确切地知道发生了什么。
        1. 确保 @article 是通过每个控制器操作的前操作(或 @articles 用于索引操作)生成的
        2. 只需在控制器顶部写一行load_and_authorize_resource after 设置模型实例的前操作
          • 请注意,唯一的区别是现在开发人员负责加载正确的模型实例,而 cancancan 不会试图猜测它。我更喜欢这种方法,因为只需一个错误就可以意外允许不应授予的访问权限。
    • 还请记住,load_and_authorize_resource 应始终任何设置模型实例变量的操作之前

    可能也有帮助的随机笔记

    • 实例变量的名称取决于动作。如果我们有一个文章控制器,那么:

      • 对于索引操作,授权查找@articles
      • 对于所有其他操作,授权查找@article
        • 然后检查是否允许用户访问该资源。
    • load_and_authorize_resource 检查模型实例是否存在,如果不存在,则创建一个。因此,如果您有一个创建 @article/@articles 的 before 操作,那么 load_and_authorize_resource 不会为您执行此操作(即它不会覆盖它),但如果您没有设置一个,cancan 将尝试设置一。有关更多信息,请参阅here

    • 能力规则将覆盖之前的规则。 (示例见here

    • 最后一件事,千万不要在ability.rb中使用current_user,它会默默地出错(!!),所以一定要使用user :)

    【讨论】:

    • 这是一个很好的解释,澄清了一些事情。感谢您写这篇文章,它有帮助!
    【解决方案2】:

    这是正在发生的事情:https://github.com/CanCanCommunity/cancancan/blob/585e5ea54c900c6afd536f143cde962ccdf68607/lib/cancan/controller_additions.rb#L342-L355

    
        # Creates and returns the current user's ability and caches it. If you
        # want to override how the Ability is defined then this is the place.
        # Just define the method in the controller to change behavior.
        #
        #   def current_ability
        #     # instead of Ability.new(current_user)
        #     @current_ability ||= UserAbility.new(current_account)
        #   end
        #
        # Notice it is important to cache the ability object so it is not
        # recreated every time.
        def current_ability
          @current_ability ||= ::Ability.new(current_user)
        end
    

    【讨论】:

    • +1 指出这个文件,它似乎解答了关于 cancancan 的所有谜团。我认为these 行有助于解释为什么它令人困惑 - 文档中没有真正描述很多魔法
    • 还有“如果实例变量已设置,则不会加载资源。”。我还没有弄清楚自定义控制器操作的默认行为是什么,但我会继续阅读。
    猜你喜欢
    • 1970-01-01
    • 2016-03-13
    • 1970-01-01
    • 2019-09-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-25
    • 2016-03-16
    • 2011-05-04
    相关资源
    最近更新 更多