cancancan 如何设置模型实例,以及如何检查它? 更新我想出了它可能发生的原因但我仍然不知道如何诊断它还剩下什么?cancancan 的工作原理随机笔记也有帮助

问题描述

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

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

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])。我不确定如何设置实例模型,但我知道它不是通灵的,所以它不知道是将它设置为当前用户的医师实例,还是传入的医师 ID 的医师实例。>

还剩下什么?

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

有帮助的小笔记:

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

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

解决方法

这是正在发生的事情: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
,

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

TL;DR,cancancan 做出了很多 细微的假设,您从一开始就不会知道这些假设。我通过彻底阅读康康康康舞会readmecodedefining abilities docs

中的评论发现了其中的许多

就这样吧..

cancancan 的工作原理

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

随机笔记也有帮助

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

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

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

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...