【问题标题】:Pundit::AuthorizationNotPerformedErrorPundit::AuthorizationNotPerformedError
【发布时间】:2021-02-19 09:52:38
【问题描述】:

这就是我在食谱展示页面上的内容:

我的控制器看起来像这样:

class RecipesController < ApplicationController
  skip_before_action :authenticate_user!, only: [:index, :show]
  def index
    if params[:query].present?
      @recipes = policy_scope(Recipe).search_by_title_and_description(params[:query]).order(created_at: :desc)
    else
      @recipes = policy_scope(Recipe).order(created_at: :desc)
    end
  end

  def show
    @recipe = Recipe.find(params[:id])
    @recipes = Recipe.first(5)
  end
end

我的政策.rb:

class RecipePolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      scope.all
    end

    def index?
      false
    end

    def show?
      false
    end
  end
end

这是将“授权@recipe”添加到显示操作时的错误消息: 我需要 Pundit 对每个配方的 cmets 的授权,而不是配方展示动作本身的授权。我做错了什么?感谢您的帮助!!

【问题讨论】:

  • 您的show? 方法已硬编码false。因此,在任何情况下都不允许用户查看任何配方。我建议阅读 Pundit 文档中的 how to define policy rules。有一些很好的例子。
  • @spickermann 是否通过编写 - def show 在 policy.rb 中硬编码?假结束 - ?
  • 是的,当show? 方法返回false 时,这意味着当前用户无权查看当前recipe。您需要将false 替换为在您的应用程序上下文中有意义的代码,并且当当前用户被允许查看特定配方时返回true(仅)。

标签: ruby-on-rails ruby rubygems pundit


【解决方案1】:

authenticate_user!(您没有向我们展示/解释过,但可能是来自devise 或类似的方法?)大概与登录有关——那就是身份验证,而不是授权,因此超出了Pundit 试图解决的范围。

身份验证就是检查“您是否已登录?”。如果此检查失败,则服务器以401 status 响应。

授权是关于检查“您是否允许执行此操作(可能作为访客)?”。如果此检查失败,则服务器以403 status 响应

现在大概,您还在应用程序中添加了一些类似这样的代码:

class ApplicationController < ActionController::Base
  include Pundit
  after_action :verify_authorized, except: :index # !!!!!
end

这张after_action支票是一张安全网;它的存在是为了确保您永远不会忘记授权端点——因为这将允许任何用户执行该操作,默认情况下!此检查的存在是导致上述错误的原因。

所以。解释完之后,让我们看看如何实现它。

  1. RecipesController#show 是否应该由客人访问,还是只能由登录用户访问?

当且仅当答案是“客人”时,添加以下内容:

skip_before_action :authenticate_user!, only: :show
  1. 假设您已经执行了任何必要的身份验证,您希望让任何用户看到任何recipe。你如何实现它?

选项 1(推荐):

class RecipePolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      scope.all
    end
  end ## WARNING!! NOTICE THAT THE `Scope` CLASS ENDS HERE!!!

  def show?
    true # !!!!
  end
end

class RecipesController < ApplicationController
  # ...
  def show
    @recipe = Recipe.find(params[:id])
    authorize(@recipe) # !!!
    # ...
  end
end

选项 2(也有效,但更糟糕的做法是因为这意味着您不能依赖策略类的单元测试):

class RecipesController < ApplicationController
  def show
    skip_authorization # !!!
    @recipe = Recipe.find(params[:id])
    # ...
  end
end

【讨论】:

  • 非常感谢您的回答!!我尝试了这两个选项,但只有选项 2 适用于 atm。也许是因为我有' before_action :authenticate_user! ' 在我的 ApplicationController 中?非常感谢您的解释,再次感谢!
  • @Witta 您是否注意到“警告!!请注意Scope 课程到此结束!!!”?你原来的策略没有按照你的想法做,因为你在错误的类中定义了方法。
  • 正如我在帖子中所说,authenticationauthorization 是不同的东西。他们是独立的。不要混淆它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多