如何通过CanCanCan获取用户的全部动态权限(含分支权限)?
问题
我正在编写API,需要向API用户暴露包含ID及其他信息的所有可用权限。现有如下模型结构:
class User < ApplicationRecord has_many :permissions, dependent: :destroy end class Permission < ApplicationRecord belongs_to :user, dependent: :destroy end
对应的Ability类:
class Ability include CanCan::Ability def initialize(user) user_permissions(user) dynamic_permissions(user) end def user_permissions(user) can :manage, :dashboard if user.admin? end def dynamic_permissions(user) user.permissions.each do |permission| #... next branch_permissions(permission) if permission.subject_class == 'branch' end end def branch_permissions(permission) can permission.action.to_sym, Branch, id: permission.allowed_ids end end
我希望在控制器中获取该用户所有的can和cannot权限,查阅文档后使用#permissions方法,但它无法识别为Branch设置的动态权限。
期望的结果格式(伪代码):
Ability.new(User.find(params[:id])).dynamic_permissions => # {:can=>{:manage=>{"dashboard"=>[]}, :read=>{"Branch"=>['id1', 'id2']}, :index=>{"Branch"=>['id1', 'id2']}, :show=>{"Branch"=>['id1', 'id2']}}, :cannot=>{}}
但当前#permissions仅返回硬编码的静态权限:
{:can=>{:manage=>{"dashboard"=>[]}, :read=>{"Branch"=>[]}, :index=>{"Branch"=>[]}, :show=>{"Branch"=>[]}}, :cannot=>{}}
我知道可以编写自定义方法,但想了解官方认可的实现方式。
官方认可的解决方案
CanCanCan的#permissions方法是简化的权限摘要,仅返回动作和主体类型,不会解析规则中附带的条件(比如你代码里的id: permission.allowed_ids)。官方推荐直接操作Ability实例的rules集合,从中提取完整权限信息。
步骤1:解析Ability的rules集合
每个CanCan::Rule实例包含权限的动作、主体、条件等完整信息,遍历该集合即可提取所需字段:
def user_permissions_details(user) ability = Ability.new(user) result = { can: {}, cannot: {} } ability.rules.each do |rule| action_key = rule.base_behavior ? :can : :cannot actions = rule.actions.is_a?(Array) ? rule.actions : [rule.actions] subject = rule.subject_type || rule.subject_class.to_s conditions = rule.conditions || {} actions.each do |action| result[action_key][action] ||= {} # 提取allowed_ids,无则返回空数组 allowed_ids = conditions[:id] || [] result[action_key][action][subject] = allowed_ids end end result end
步骤2:在控制器中调用
用这个方法就能得到包含ID列表的完整权限:
def show user = User.find(params[:id]) permissions = user_permissions_details(user) render json: permissions end
关键参数说明
rule.base_behavior:判断当前规则是can还是cannot类型rule.actions:获取权限对应的动作(可能是单个动作或数组)rule.subject_class/rule.subject_type:获取权限对应的主体类名称rule.conditions:获取权限的条件哈希,从中提取allowed_ids
这种方式是官方文档推荐的自定义权限序列化方案,因为rules是Ability内部存储所有权限规则的核心集合,能完整保留所有权限细节。
内容的提问来源于stack exchange,提问作者zhisme
相关产品推荐
相关产品推荐

