Active Admin、Devise 和 Pundit (Pundit::PolicyScopingNotPerformedError)
Active Admin, Devise and Pundit (Pundit::PolicyScopingNotPerformedError)
我有一个现有的 Rails 应用,其中 Devise
对 User
模型进行身份验证,Pundit
针对链接 User
的 Enrollment
模型进行身份验证] 到我的 Company
模型。 User
和 Company
都在公寓 gem 的 public 架构中。我不怀疑公寓是问题的一部分,但我想我会提到它。
我使用 AdminUser 添加了 Active Admin class - 我想将我的管理员用户与应用程序用户分开。
如果我尝试访问 /admin
或 /admin/dashboard
,我得到:
Pundit::PolicyScopingNotPerformedError at /admin/users
Pundit::PolicyScopingNotPerformedError
如果我尝试像 /admin/users
这样的模型,Pundit 似乎会忽略 active_admin 政策并转到主要应用程序政策。在我的例子中,应用程序抛出异常,因为它期望 Enrollment
与 AdminUser
.
如果我禁用:
##/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
以下是可以找到的关于此问题的相关 post:
https://gorails.com/forum/using-pundit-with-activeadmin
我希望在此 post (Can you disable Pundit with Devise and Active Admin?) 中一起禁用 Pundit,但让它工作会很好。
更新
我已经解决了,但我仍然不知道这是否应该开箱即用,而且我有一些奇怪的问题导致了所有这些。要点已更新。
我最终使用了:
https://viget.com/extend/8-insanely-useful-activeadmin-customizations
还有一点:
Documentation for conditional before_action/before_filter
和下面的一些答案。我硬塞进一个过滤器以强制 AA 调用对 AA 内部资源和集合的授权。接下来是添加策略范围,但现在我的脑袋太疼了。
我还必须添加另一个过滤器来绕过仪表板上的身份验证,因为它是无头的。到目前为止似乎有效。
更新 2
嗯……我想我说得太早了。只有当我以常规方式登录时,这一切才有效 User
- 如果我注销,一切都会再次崩溃。
您可以使用 skip_policy_scope
跳过 Active Admin 控制器中的范围界定吗?
If you're using verify_authorized
in your controllers but need to
conditionally bypass verification, you can use skip_authorization
. For
bypassing verify_policy_scoped
, use skip_policy_scope
.
@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 过滤器之后,我们可以访问 "resource" 并且我们可以像通常对任何模型实例一样对其进行授权。参见:https://github.com/activeadmin/activeadmin/issues/1108#issuecomment-14711733
首先需要策略范围的原因是因为正常的专家安装需要 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。
我有一个现有的 Rails 应用,其中 Devise
对 User
模型进行身份验证,Pundit
针对链接 User
的 Enrollment
模型进行身份验证] 到我的 Company
模型。 User
和 Company
都在公寓 gem 的 public 架构中。我不怀疑公寓是问题的一部分,但我想我会提到它。
我使用 AdminUser 添加了 Active Admin class - 我想将我的管理员用户与应用程序用户分开。
如果我尝试访问 /admin
或 /admin/dashboard
,我得到:
Pundit::PolicyScopingNotPerformedError at /admin/users
Pundit::PolicyScopingNotPerformedError
如果我尝试像 /admin/users
这样的模型,Pundit 似乎会忽略 active_admin 政策并转到主要应用程序政策。在我的例子中,应用程序抛出异常,因为它期望 Enrollment
与 AdminUser
.
如果我禁用:
##/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
以下是可以找到的关于此问题的相关 post:
https://gorails.com/forum/using-pundit-with-activeadmin
我希望在此 post (Can you disable Pundit with Devise and Active Admin?) 中一起禁用 Pundit,但让它工作会很好。
更新
我已经解决了,但我仍然不知道这是否应该开箱即用,而且我有一些奇怪的问题导致了所有这些。要点已更新。
我最终使用了:
https://viget.com/extend/8-insanely-useful-activeadmin-customizations
还有一点:
Documentation for conditional before_action/before_filter
和下面的一些答案。我硬塞进一个过滤器以强制 AA 调用对 AA 内部资源和集合的授权。接下来是添加策略范围,但现在我的脑袋太疼了。
我还必须添加另一个过滤器来绕过仪表板上的身份验证,因为它是无头的。到目前为止似乎有效。
更新 2
嗯……我想我说得太早了。只有当我以常规方式登录时,这一切才有效 User
- 如果我注销,一切都会再次崩溃。
您可以使用 skip_policy_scope
跳过 Active Admin 控制器中的范围界定吗?
If you're using
verify_authorized
in your controllers but need to conditionally bypass verification, you can useskip_authorization
. For bypassingverify_policy_scoped
, useskip_policy_scope
.
@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 过滤器之后,我们可以访问 "resource" 并且我们可以像通常对任何模型实例一样对其进行授权。参见:https://github.com/activeadmin/activeadmin/issues/1108#issuecomment-14711733
首先需要策略范围的原因是因为正常的专家安装需要 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。