6

我对如何正确配置 CanCanCan 有点困惑。

对于初学者,我是否必须添加load_and_authorize_resource到我想限制访问的每个控制器资源?

这就是我想做的:

  • 管理员可以管理和访问所有控制器和操作
  • 编辑可以阅读所有,管理:新闻室,并可以管理所有帖子
  • 会员可以阅读每个帖子,可以创建和更新帖子(不能编辑/删除/其他任何内容),不能访问新闻编辑室。我们的业务规则中更新和编辑帖子之间的区别在于,更新是创建一个新帖子,它是当前帖子的子帖子。所以不是编辑。只是与祖先关联的新记录。
  • 访客可以阅读每个帖子,但不能创建帖子或访问新闻编辑室。

这就是我的ability.rb样子:

class Ability
  include CanCan::Ability
  def initialize(user)
    user ||= User.new # guest user (not logged in)
    #Admin
   if user.has_role? :admin
        can :manage, :all
        can :manage, :newsroom
   # Editor
    elsif user.has_role? :editor
      can :read, :all
      can :manage, :newsroom
      can :manage, Post
    #Member
    elsif user.has_role? :member
        can :read, :all
        can :create, Post
        can :status, Post
        can :update, Post do |post|
            post.try(:user) == user
        end
    #Guest
    else
        can :read, :all
        can :create, Post
        can :status, Post
    end    
  end
end

在我的routes.rb我有这个:

  authenticate :user, lambda { |u| u.has_role? :admin or :editor } do
    get 'newsroom', to: 'newsroom#index', as: "newsroom"
    get 'newsroom/published', to: 'newsroom#published'
    get 'newsroom/unpublished', to: 'newsroom#unpublished'    
  end

但发生的情况是,当我使用尚未分配任何角色的用户(即我想成为“访客”)登录时,他们可以访问新闻编辑室。

当我尝试编辑角色为 的帖子时:member,它给了我一个“未授权编辑帖子”错误(这是正确的)。

我只是不能完全锁定Newsroom,我不知道为什么。

4

4 回答 4

11

您不需要load_and_authorize_resource在每个控制器中使用。这是一个方便的宏,它做两件事。首先,它使用为当前控制器和操作假定的记录分配一个实例变量。然后它授权资源。对于某些控制器操作,第一步可能是错误的,因此您需要加载资源,然后手动对其进行授权。Railscasts 一集中关于 CanCan的一个例子是这样的:

def edit
  @article = Article.find(params[:id])
  unauthorized! if cannot? :edit, @article
end

您也可以像在CanCan Wiki 上的示例中那样对控制器进行授权

def show
  @project = Project.find(params[:project])
  authorize! :show, @project
end

或者您可以authorize_resource自己使用并负责加载它。最后,您必须确保 CanCan 以某种方式用于授权(控制器宏或在每个操作中)。关于你的能力,我认为你想要这样的东西:

class Ability
  include CanCan::Ability
  def initialize(user)
    user ||= User.new # guest user (not logged in)
    #Admin
    if user.has_role? :admin
      can :manage, :all
    # Editor
    elsif user.has_role? :editor
      can :read, :all
      can :manage, :newsroom
      can :manage, Post
    #Member
    elsif user.has_role? :member
      can :read, :all
      can :create, Post
      can :status, Post
      can :update, Post do |post|
        post.try(:user) == user
      end
    #Guest
    else
      can :read, :all
      cannot [:index, :published, :unpublished], :newsroom
    end
  end
end

这是一个示例,例如您可以如何授权您的新闻编辑室:

class ToolsController < ApplicationController
  authorize_resource :class => false
  def show
  # automatically calls authorize!(:show, :tool)
  end
end

关于 CanCan 的最后一点个人说明是,我不建议将它用于新项目,因为它不再被积极维护,而且在定义能力时我发现它有点违反直觉。也就是说,CanCan 是我使用过的文档最完整的 gem 之一,尤其是 wiki有大量的示例和解释。

于 2014-12-16T09:48:30.327 回答
3
can :read, :all

表示用户有权读取您应用的所有资源。它应该是

can :read, Post

还添加

cannot :manage, :newsroom

您不想访问新闻编辑室的地方。您指定权限的顺序很重要。正如其他人已经提到的,“load_and_authorize_resource”是可选的。只需要“授权资源”来授权控制器的所有操作。如果您跳过这些,那么您可以“授权”单个控制器操作。

除非绝对必要,否则避免使用技能块。例如,如果 Post 中有一个 user_id ,那么你可以这样做

can :update, Post, user_id: user.id

最后,在没有模型支持控制器的情况下使用“class => false”。即,您没有名为“Newsroom”的模型,但您有一个名为“NewsroomsController”的控制器。

于 2014-12-20T18:23:51.230 回答
2

为了它的价值,我不得不这样设置NewsroomController

class NewsroomController < ApplicationController
  authorize_resource :class => false

这是我的工作版本ability.rb在我获得所需权限后的样子:

#Roles
#Admin
 if user.has_role? :admin
      can :manage, :all
 # Editor
  elsif user.has_role? :editor
    can :manage, :newsroom
    can :manage, Post
  #Member
  elsif user.has_role? :member
      can [:read, :create, :status], Post
      can :update, Post do |post|
        post.try(:user) == user
      end
  #Guest
  else
      can [:read, :status], Post
  end
于 2014-12-17T22:41:25.300 回答
1

对于初学者,我是否必须将 load_and_authorize_resource 添加到我想要限制访问的每个控制器资源中?

是的。

但发生的情况是,当我使用尚未分配任何角色的用户(即我想成为“访客”)登录时,他们可以访问新闻编辑室。

从上面的客人角色:

...
#Guest
else
    can :read, :all
    can :create, Post
    can :status, Post
end    

这使访客可以读取所有内容以及创建帖子的能力。如果您希望您的客人只能阅读帖子,则应该是:

...
#Guest
else
    can :read, Post
    # can :status, Post # maybe you want this aswell
end   
于 2014-12-16T08:06:29.980 回答