如何使用Pundit为所有控制器动作授权?是否应采用该方案?
用Pundit实现全局控制器动作授权(管理员全权限,Editor默认全拒再开白名单)
1. 编写基础父Policy(ApplicationPolicy)
所有业务Policy都继承这个类,实现全局默认权限规则:
# app/policies/application_policy.rb class ApplicationPolicy attr_reader :user, :record def initialize(user, record) @user = user @record = record raise Pundit::NotAuthorizedError, "必须登录才能操作" unless user end # 默认所有动作仅允许管理员访问,Editor无权限 def index?; admin?; end def show?; admin?; end def create?; admin?; end def new?; admin?; end def update?; admin?; end def edit?; admin?; end def destroy?; admin?; end private # 判断是否为管理员 def admin? user.role == 'admin' end # 预留Editor判断方法,后续开权限用 def editor? user.role == 'editor' end end
2. 业务Policy继承父类
比如CD资源的Policy,默认继承所有父类的权限规则,后续需要给Editor开权限时再重写对应方法:
# app/policies/cd_policy.rb class CdPolicy < ApplicationPolicy # 示例:后续允许Editor创建和更新CD信息时,取消注释以下代码 # def create?; admin? || editor?; end # def update?; admin? || editor?; end end
3. 全局控制器授权(避免逐个动作写authorize)
在ApplicationController中添加全局授权逻辑,所有控制器的所有动作都会自动触发权限校验:
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base include Pundit::Authorization # 全局校验所有动作权限,可在特定控制器跳过 before_action :authorize_request private def authorize_request # 自动匹配当前控制器对应的Policy类 policy_class = "#{controller_name.classify}Policy".constantize # 根据动作类型处理record参数(适配index/new等无需实例的动作) record = case action_name when 'new', 'create' controller_name.classify.constantize.new when 'index' controller_name.classify.constantize else send(controller_name.singularize) # 比如show/edit动作取@cd实例 end # 触发对应动作的权限校验 authorize(record, "#{action_name}?") end # 处理授权失败的提示 rescue_from Pundit::NotAuthorizedError do |_e| redirect_to root_path, alert: "无权限执行此操作" end end
4. 跳过特定动作的授权(可选)
如果有不需要权限校验的页面(比如首页),在对应控制器中添加跳过逻辑:
# app/controllers/home_controller.rb class HomeController < ApplicationController skip_before_action :authorize_request, only: [:index] def index; end end
核心逻辑说明
- 管理员默认拥有所有控制器所有动作的权限
- Editor默认被拒绝所有操作,后续需要开放某个控制器的某个动作时,只需在对应业务Policy中重写该动作的校验方法(比如
def create?; admin? || editor?; end) - 全局授权逻辑避免了在每个控制器每个动作中重复编写
authorize调用,减少冗余代码
内容的提问来源于stack exchange,提问作者fugee ohu
相关产品推荐
相关产品推荐

