Rails-将Pundit与单独的管理名称空间配合使用

时间:2018-08-23 01:04:37

标签: ruby-on-rails devise authorization ruby-on-rails-5 pundit

我目前让Devise和Pundit在一个封闭的系统中运行良好,该系统要求用户登录才能看到任何东西。

新目标:如何使用Pundit要求AdminUser登录才能访问Admin名称空间?

我有一个单独的AdminUser模型,一个单独的Admin控制器,策略和命名空间:

routes.rb

namespace :admin do
  root to: 'home#index'
  resources :users
end

devise_for :admin_users, skip: [:sessions]
as :admin_user do
  get 'admin/signin', to: 'admin/devise/sessions#new', as: :new_admin_user_session
  post 'admin/signin', to: 'admin/devise/sessions#create', as: :admin_user_session
  delete 'admin/signout', to: 'admin/devise/sessions#destroy', as: :destroy_admin_user_session
end

controllers / admin / admin_controller.rb

class Admin::AdminController < ApplicationController

end

controllers / admin / home_controller.rb

class Admin::HomeController < Admin::AdminController

  def index
    authorize [:admin, :home]
  end

end

policies / admin / admin_policy.rb (已关闭系统,当前查找的是User而不是AdminUser)

class Admin::AdminPolicy
  attr_reader :user, :record

  def initialize(user, record)
    # Must be logged in
    raise Pundit::NotAuthorizedError, "You must be logged in to perform this action" unless user
    @user = user
    @record = record
  end

  def index?
    false
  end

  def show?
    false
  end

  def create?
    false
  end

  def new?
    create?
  end

  def update?
    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      raise Pundit::NotAuthorizedError, "You must be logged in to perform this action" unless user
      @user = user
      @scope = scope
    end

    def resolve
      scope.all
    end
  end
end

policies / admin / home_policy.rb (管理员命名空间的子策略示例)

class Admin::HomePolicy < Admin::AdminPolicy

  def index?
    user.present?
  end

end

这两个策略的设置方式都与我的用户策略相同,因此,它们都不在寻找AdminUser。如何在AdminUser模型中使用这些功能?

1 个答案:

答案 0 :(得分:1)

我认为您在正确的轨道上。您已经为您的管理控制器创建了一个命名空间,该命名空间继承自Admin::AdminController。 Pundit向您的ApplicationController注入一个名为pundit_user的辅助方法,默认情况下,该方法仅返回current_user

尽管您可以考虑不为管理员使用单独的模型,而是使用适当的授权设置,但这可能并不适合所有情况。我只想把它放在那里供您考虑。

解决这个问题的最简单方法就是简单地覆盖Admin::AdminController中的helper方法,如下所示:

class Admin::AdminController < ApplicationController
  def pundit_user
    current_admin_user
  end
end

请注意,这确实是假设AdminUser模型是在this convention行的某处设置的