如何使用Devise/CanCan来保护已挂载的引擎资源?

8

我有一个引擎安装在我的主应用程序中,我想保护该引擎内的某些控制器和操作。

该引擎是通过以下方式挂载的:

mount SomeEngine::Engine => '/some_engine'

Devise/CanCan与主应用程序的其余控制器和操作配合使用,但在没有其他任何内容的情况下运行会产生此错误:

This action failed the check_authorization because it does not authorize_resource. Add skip_authorization_check to bypass this check.

我使用修饰器的方法从主应用程序中打开引擎控制器并添加:

load_and_authorize_resource

然后我遇到了这个错误:
No route matches {:action=>"new", :controller=>"devise/sessions"}

我可以使用以下方法使事情工作起来,但在实现角色时会感到笨重:
authenticate :administrator do
  mount SomeEngine::Engine => '/some_engine'
end

我所说的“笨重”是指我必须为每个具有访问引擎权限的角色在routes.rb文件中复制上述代码块……除非有另一种使用角色进行身份验证的方法,这是我不知道的吗?
如果可能的话,我想在控制器中使用普通的Devise/CanCan授权/身份验证方法。但是我认为“没有路由匹配”错误是因为引擎不知道如何进入主应用程序的Devise控制器。但是我如何从主应用程序解决这个问题呢?
还有一个问题要考虑……引擎中有一个特定的控制器/操作,我希望所有用户都可以访问。到目前为止,我只是将其添加到routes.rb文件中身份验证代码块之前。
match '/some_engine' => 'some_engine/some_controller#public_action'

它能够工作……但是在routes.rb中使用块的这一行似乎我做错了什么。这也不允许我很好地实现角色。

1个回答

8
你可以继承应用程序控制器以使用Devise和CanCan,这可以从主应用程序中实现。
module SomeEngine
  class ApplicationController < ::ApplicationController    
    before_filter :merge_abilities

    private

    def merge_abilities
      current_ability.merge(SomeEngine::Ability.new(current_user))                                                     
    end
  end
end                                                                                                                     

之后,您可以创建自己的能力来为引擎增加功能。

module SomeEngine
  class Ability
    include ::CanCan::Ability

    def initialize(user)
      return if user.nil?

      can :manage, SomeModel
    end
  end
end

SomeModel (SomeEngine::SomeModel) 是 SomeEngine 引擎中的模型。

在资源控制器中,您必须指定资源的类名。

load_and_authorize_resource class: SomeEngine::SomeModel

如果您想在引擎中使用它,请不要忘记将路由助手更改为main_app.MAIN_APP_PATHS 在主应用程序布局中。


哇,我不知道你可以合并这些能力。最终我按照Forem和Spree宝石中使用的模式进行了跟踪。你的模式基本上就是他们所做的,但增加了能力的合并。谢谢! - Zhao Li

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