使用CanCan实现上下文感知授权

7
我希望使用CanCan来处理权限。我的网站有许多不同的权限级别,并且大部分都是上下文感知的。例如,在我的三个主要模型中,以下是它们之间的关系:
class User < ActiveRecord::Base
  has_many :league_relations
  has_many :leagues, :through => :league_relations
end

class League < ActiveRecord::Base
  has_many :league_relations
  has_many :users, :through => :league_relations
end

class LeagueRelation < ActiveRecord::Base
  belongs_to :user
  belongs_to :league
end

注意,LeagueRelations是Leagues的嵌套资源。我想让用户修改联赛,并根据存储在league_relation中的数据来衡量每个用户的授权。然后,我希望用户仅基于用户模型中存储的数据来修改联赛关系。
简而言之:我基本上希望使用LeagueRelations来授权League操作,而使用Users来授权LeagueRelations操作。例如,league_relation.owner = true可以删除一个League,但是必须通过user.owner?才能删除LeagueRelation。当在联赛控制器内部时,如何基于league_relation的属性进行授权,并在其他控制器上的其他模型上授权其他操作。如果需要更多澄清,请留下评论。
谢谢。
1个回答

10

好的,我解决了问题。我的用例在CanCan的README开头简要提到,但是我错过了它。你可以在app/models/中定义新的Ability类,该类可以接受与current_user不同的参数。要这样做,请将以下内容放入您的控制器中:

def current_ability 
  if params[:controller] == 'leagues'
    @current_ability = LeagueAbility.new(current_user_league_relation)
  elsif params[:controller] == 'league_relations'
    @current_ability = LeagueRelationAbility.new(current_user_league_relation)
  else
    @current_ability = Ability.new(current_user)
  end
end

现在您可以在 app/models/ 中创建 league_ability.rb。

class LeagueAbility
  include CanCan::Ability

  def initialize(league_relation)
    league_relation ||= LeagueRelation.new

    if league_relation.owner?
      can :manage, League, :id => league_relation.league_id
    elsif league_relation.moderator?
      can :manage, League, :id => league_relation.league_id
      cannot [:delete, :destroy], League
    else
      can :read, League
      can :create, League
    end    
  end
end

需要注意的是,这取决于你的应用控制器调用子类中的方法。希望这可以帮助!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接