设置 CanCan 的 ability.rs 模型

4
我成功地使用Devise和CanCan创建了登录系统,并拥有3种类型的用户:管理员、内部用户和全局用户。我创建了控制器和索引操作:Admin、Cpanel、Report和State,并希望限制某些用户访问这些控制器。
管理员用户应该有权限访问:报告(全部)、状态(读取)、管理(全部)。
全局用户应该有权限访问:报告(只读)、状态(读取)、控制面板(全部)。
内部用户应该有权限访问:报告(全部)、状态(读取)。
我尝试使用ability.rs中的以下代码来实现此功能。
class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)

    if user.role? :admin
      can :manage, [Report, Admin]
      can :read, State
    elsif user.role? :global_user
      can :read, [Report, State]
      can :manage, Cpanel
    elsif user.role? :internal_user
      can :manage, Report
      can :read, State     
    end
   end
end

目前,这个控制器中只有索引操作。当我使用内部用户登录应用程序时,我可以访问例如/admin的页面,这不是我想要的行为。我希望限制对所有控制器的访问,而不是ability.rb类中列出的控制器。

源代码在这里

3个回答

8
如果我想要防止访问整个控制器,我会创建一个 before 过滤器,如果用户没有管理员角色,则重定向用户到一个访问被拒绝的页面。代码可能如下所示:
def check_permissions
 raise CanCan::AccessDenied unless @current_user.role?(:admin)
end

如果我只想防止更新和创建的访问,例如,我会这样做:
def update
  raise CanCan::AccessDenied unless can?(:update,Thing)
  ...
end

def create
  raise CanCan::AccessDenied unless can?(:create,Thing)
  ...
end

您可以在应用程序控制器中处理CanCan::AccessDenied异常:
rescue_from CanCan::AccessDenied do |exception|
    flash[:error] = exception.message
    redirect_to no_access_path
  end

我有关于CanCan和Devise的一些非常好的帖子,这里这里更新 我在我的应用程序控制器中使用此方法来设置当前用户变量:
# Make the current user object available to views
  #----------------------------------------------------------------------------
  def get_user
    @current_user = session[:current_user]
  end

为什么我会得到“undefined method 'role?' for nil:NilClass”这个错误? - dormitkon
我在用户模型中有一个方法叫做role? - dormitkon
这意味着你在 nil 上调用了 role? 方法。如果你使用了我上面的代码,那么你的 @current_user 对象是 nil。你需要确保它被设置了。请参考我上面的编辑来了解我是如何做到的。 - Tony

2

您需要在控制器中添加cancan授权检查。

这可能只需要添加一行代码,例如:

authorize! :read, @state

针对你的状态控制器索引操作,以及所有其他索引操作,需要进行翻译。

编辑: 抱歉,在状态控制器索引操作中,可能没有@state,因此上述内容不适用。可能需要类似以下内容:

authorize! :read, State

还有一个load_and_authorize方法,可以用于将多个操作的授权组合在控制器中并减少代码。 load_and_authorize版本可能类似于

load_and_authorize_resource :state

它应该放在您的操作之前。
您可能需要查看这个Cancan授权的Railscast,了解完整的基本设置(Rails2)。
我怀疑为了解决其他问题,我们可能需要看到更多的代码。 尝试发布一些控制器代码。
我没有在Rails3中使用这个功能,但我认为大部分内容仍然相似。

我无法访问/state,即使使用具有权限的用户也不行。 - dormitkon
我在Admin控制器的index操作中添加了“authorize!:index,Admin”。现在,当我作为全局用户访问/ admin时,我会在AdminController#index中获得NameError uninitialized constant AdminController :: Admin。整个应用程序在此处: http://cl.ly/2E292R2m2B0X141q3C0S - dormitkon
:index 应该仍然是 :read - 但我会查看您的整个控制器,看看是否有任何问题。 - Don Roby
您的代码中不存在管理员。Cancan的简单示例和我的所有代码都假定有一个受保护的模型。在没有模型的情况下,我不太清楚如何使用它,但也许其他人可以帮忙。您肯定需要在控制器中进行一些操作,但在这种情况下我不太确定应该做什么。 - Don Roby

0

我用以下方法解决了这个问题

def check_permissions
 raise CanCan::AccessDenied unless current_user.role?(:admin)
end

但是请注意,我必须将@current_user更改为current_user(不带@符号)

谢谢Tony


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