Active Admin,Devise和Pundit(Pundit :: PolicyScopingNotPerformedError)

时间:2016-01-07 20:35:10

标签: ruby-on-rails devise activeadmin pundit

我有一个现有的Rails应用,DeviseUser模型进行身份验证,PunditEnrollment模型进行身份验证,该模型将UserCompany相关联模型。 UserCompany都位于公寓gem的公共架构中。我不怀疑公寓是问题的一部分,但我想我会提到它。

我使用AdminUser类添加了Active Admin - 我希望将我的管理员用户与应用用户分开。

如果我尝试访问/admin/admin/dashboard,我会:

Pundit::PolicyScopingNotPerformedError at /admin/users
Pundit::PolicyScopingNotPerformedError

如果我尝试像/admin/users这样的模型,Pundit似乎会忽略active_admin政策并转到主应用政策。在我的情况下,该应用会抛出异常,因为它期待EnrollmentAdminUser的对比。

如果我禁用:

##/config/initializers/active_admin.rb
  config.authorization_adapter = ActiveAdmin::PunditAdapter

##/controllers/application_controller
  after_action :verify_authorized, except: [:landing, :dashboard], unless: :devise_controller?
  after_action :verify_policy_scoped, only: [:index]

这一切都有效,但后来我在主应用程序中失去了Pundit等。

以下是我的代码的要点:

https://gist.github.com/jasper502/4b2f1b8b6f21a26c64a5

以下是可以在此问题上找到的相关帖子:

https://gorails.com/forum/using-pundit-with-activeadmin

How to get Active Admin to work with Pundit after login

我希望在这篇文章(Can you disable Pundit with Devise and Active Admin?)中一起禁用Pundit,但这样做会很好。

更新

我有解决方法,但我仍然不知道这是否应该开箱即用,我有一些奇怪的问题导致所有这一切。 Gist已更新。

我最终使用了:

https://viget.com/extend/8-insanely-useful-activeadmin-customizations

和一点:

Documentation for conditional before_action/before_filter

以下一点答案。我在过滤器中使用过强制AA来强制AA对AA内的资源和集合进行授权。接下来是添加策略范围,但我的大脑现在伤得太厉害了。

我还必须在仪表板上添加另一个过滤器以绕过身份验证,因为它无头。似乎到目前为止工作。

更新2

嗯......我想我说得太早了。这一切只有在我以常规User登录时才有效 - 如果我退出,它会再次崩溃。

2 个答案:

答案 0 :(得分:5)

@ dan-tappin我想你已经根据你的评论发现了一个类似的解决方案,但这里是我最后添加到我的每个AA模型注册中的内容:

#app/admin/user.rb
ActiveAdmin.register User do
  controller do
    before_filter :authorize_index, only: :index
    def authorize_index
      policy_scope(User)
    end

    before_filter :authorize_show_edit_destroy, only: [:show, :edit, :destroy]
    def authorize_show_edit_destroy
      authorize resource
    end
  end
end

基本上,这利用了使用普通rails before_filter语法在控制器范围内执行的能力来限制执行:only。然后因为before_filter发生在inherrited_resources过滤器之后,我们可以访问"资源"我们可以像对待任何模型实例一样对它进行授权。请参阅:https://github.com/activeadmin/activeadmin/issues/1108#issuecomment-14711733

首先需要策略范围的原因是因为普通的pundit安装需要application_controller.rb中的以下内容

#app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  include Pundit
  protect_from_forgery with: :exception

  #before_action :authenticate_is_admin!

  after_action :verify_authorized, except: [:index, :dashboard], unless: :devise_controller?
  after_action :verify_policy_scoped, only: :index, unless: :devise_controller?

  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  private
  def authenticate_admin!
    redirect_to new_user_session_path unless current_user.admin?
  end

  private
  def pundit_user
    current_user
  end

  private
  def user_not_authorized
    flash[:error] = "You are not authorized to perform this action."
    redirect_to(request.referrer || new_user_session_path)
  end
end

它希望调用策略范围所有索引操作的模型。仪表板控制器默认呈现索引操作,因此需要使用此before_filter hack。

答案 1 :(得分:0)

您可以使用print("foo")跳过Active Admin控制器中的范围界定吗?

请参阅documentation

  

如果您在控制器中使用skip_policy_scope但需要   有条件绕过验证,您可以使用verify_authorized。对于   绕过skip_authorization,请使用verify_policy_scoped