You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Active Admin中实现基于角色的资源访问权限控制技术问询

我之前也在Active Admin里做过类似的角色权限控制,结合你已经有的数据表结构,给你梳理几个可行的步骤:

第一步:完善模型关联与权限判断方法

首先得确保你的用户、角色、功能之间的关联是正确的,同时在用户模型里添加一个便捷的权限判断方法,方便后续调用。

假设你的表结构是:

  • functions: 存储功能列表,包含key(比如create_user)、name字段
  • roles: 存储角色列表,包含name字段(比如manager)
  • role_functions: 角色与功能的中间关联表
  • user_roles: 用户与角色的中间关联表

对应的模型代码如下:

# app/models/user.rb
class User < ApplicationRecord
  has_many :user_roles
  has_many :roles, through: :user_roles
  has_many :functions, through: :roles

  # 判断当前用户是否拥有指定功能权限
  def can_perform?(feature_key)
    functions.exists?(key: feature_key)
  end
end

# app/models/role.rb
class Role < ApplicationRecord
  has_many :role_functions
  has_many :functions, through: :role_functions
  has_many :user_roles
  has_many :users, through: :user_roles
end

# app/models/function.rb
class Function < ApplicationRecord
  has_many :role_functions
  has_many :roles, through: :role_functions
end
第二步:控制Active Admin资源的访问权限

接下来有两种主流方式实现权限控制:原生代码自定义,或者使用成熟的权限管理gem。

方式一:原生代码自定义(无需额外gem)

这种方式适合权限逻辑不复杂的场景,灵活性高。

1. 全局权限拦截(可选)

如果想统一控制所有资源的权限,可以在Active Admin的初始化文件里添加全局回调:

# config/initializers/active_admin.rb
ActiveAdmin.setup do |config|
  # 其他配置...

  config.before_action do
    authenticate_admin_user! # 确保用户已登录

    # 根据当前操作和资源生成对应的功能key,比如"create_user"
    resource_name = controller_name.singularize
    current_feature = "#{params[:action]}_#{resource_name}"

    # 允许index和show操作(可根据你的需求调整),其他操作必须检查权限
    unless ["index", "show"].include?(params[:action]) || current_admin_user.can_perform?(current_feature)
      redirect_to admin_root_path, alert: "你没有权限执行此操作"
    end
  end
end

2. 单个资源精细化控制

如果需要对某个资源做特殊处理,可以在资源配置文件里单独设置:

# app/admin/user.rb
ActiveAdmin.register User do
  controller do
    # 针对不同操作设置权限检查
    before_action :check_create_permission, only: [:new, :create]
    before_action :check_edit_permission, only: [:edit, :update]

    private

    def check_create_permission
      unless current_admin_user.can_perform?("create_user")
        redirect_to admin_users_path, alert: "你没有创建用户的权限"
      end
    end

    def check_edit_permission
      unless current_admin_user.can_perform?("edit_user")
        redirect_to admin_users_path, alert: "你没有编辑用户的权限"
      end
    end
  end

  # 控制菜单可见性:只有拥有权限的用户才能看到User菜单
  menu if: proc { current_admin_user.can_perform?("manage_users") }

  # 控制页面按钮显示:比如只给有权限的用户显示新建按钮
  action_item :new, only: :index do
    link_to "新建用户", new_admin_user_path if current_admin_user.can_perform?("create_user")
  end

  # 控制列表页的操作按钮显示
  index do
    selectable_column
    id_column
    column :email
    column :created_at
    actions do |user|
      item "编辑", edit_admin_user_path(user) if current_admin_user.can_perform?("edit_user")
      item "删除", admin_user_path(user), method: :delete, data: { confirm: "确定删除吗?" } if current_admin_user.can_perform?("destroy_user")
    end
  end

  # 控制表单字段可见性:比如只有有权限的用户才能设置用户角色
  form do |f|
    f.inputs "用户信息" do
      f.input :email
      f.input :password if current_admin_user.can_perform?("set_user_password")
      f.input :role_ids, as: :select, multiple: true if current_admin_user.can_perform?("assign_user_roles")
    end
    f.actions
  end
end

3. 提取公共逻辑(可选)

如果多个资源的权限检查逻辑重复,可以提取成一个Concern:

# app/controllers/concerns/active_admin_permissions.rb
module ActiveAdminPermissions
  extend ActiveSupport::Concern

  included do
    before_action :check_permissions
  end

  private

  def check_permissions
    action = params[:action]
    resource_name = controller_name.singularize
    feature_key = "#{action}_#{resource_name}"

    # 自定义允许跳过权限检查的操作
    skip_actions = ["index", "show"]
    unless skip_actions.include?(action) || current_admin_user.can_perform?(feature_key)
      redirect_to admin_root_path, alert: "你没有权限执行此操作"
    end
  end
end

然后在资源的controller里引入这个Concern即可:

# app/admin/user.rb
ActiveAdmin.register User do
  controller do
    include ActiveAdminPermissions
  end
end

方式二:使用Pundit(适合复杂权限场景)

如果你的权限逻辑比较复杂,推荐使用Pundit这个成熟的权限管理gem,结构更清晰。

  1. 添加gem到Gemfile:
gem 'pundit'

执行bundle install安装。

  1. 生成Pundit基础文件:
rails generate pundit:install
  1. 创建AdminPolicy类,定义权限规则:
# app/policies/admin_policy.rb
class AdminPolicy < ApplicationPolicy
  def index?
    user.can_perform?("index_#{record.class.name.underscore}")
  end

  def create?
    user.can_perform?("create_#{record.class.name.underscore}")
  end

  def update?
    user.can_perform?("edit_#{record.class.name.underscore}")
  end

  def destroy?
    user.can_perform?("destroy_#{record.class.name.underscore}")
  end

  # 自定义其他操作的权限判断,比如export?
end
  1. 在Active Admin里启用Pundit适配器:
# config/initializers/active_admin.rb
ActiveAdmin.setup do |config|
  # 其他配置...
  config.authorization_adapter = ActiveAdmin::PunditAdapter
end
  1. 在资源配置里指定Pundit用户:
# app/admin/user.rb
ActiveAdmin.register User do
  controller do
    def pundit_user
      current_admin_user
    end
  end
end

这样Pundit就会自动根据AdminPolicy里的规则判断用户是否有权限执行对应操作,同时你依然可以结合之前的菜单、按钮控制逻辑实现细粒度权限。

最后注意事项
  • 确保current_admin_user指向你的登录用户模型,Active Admin默认会使用AdminUser,如果你的用户模型是User,需要在初始化文件里配置config.authentication_method = :authenticate_user!和config.current_user_method = :current_user。
  • 测试时要覆盖不同角色的用户,确保权限控制生效,比如用manager角色测试是否能访问create_user对应的操作,用普通用户测试是否被拦截。

内容的提问来源于stack exchange,提问作者Priya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:27:50