6

我正在使用Trestle Admin,这是我的路线:

trestle_path        /admin         Trestle::Engine

当不是管理员的用户访问/admin路由时,我希望 CanCanCan 像处理我的应用程序中所有其他未经授权的请求一样处理它。

但问题是我不知道如何在我的中指定该能力,ability.rb或者我不知道在哪里添加authorize语句。

当我/admin在我的应用程序中访问时,我的日志如下所示:

Started GET "/admin" for ::1 at 2019-03-31 01:10:01 -0500
Processing by Trestle::DashboardController#index as HTML
Redirected to http://localhost:3000/admin/login
Filter chain halted as :require_authenticated_user rendered or redirected
Completed 302 Found in 13ms (ActiveRecord: 0.0ms)

因此,所发生的一切就是它重定向到/admin/loginTrestle 引擎如何处理它。

但我希望 CanCanCan 劫持并处理它,就像它通过 my 中的规则处理整个应用程序中的所有其他未经授权的请求一样application_controller.rb

rescue_from CanCan::AccessDenied do |exception|
  respond_to do |format|
    format.json { head :forbidden, content_type: 'text/html' }
    format.html { redirect_to main_app.root_url, alert: exception.message }
    format.js   { head :forbidden, content_type: 'text/html' }
  end
end

但是,鉴于它不是我定义的模型或控制器,我不确定在我的ability.rb.

我尝试了以下方法,但均无济于事:

  if user.has_role? :admin
    can :manage, :all
  else
    cannot :read, :trestle
  end

或者:

  if user.has_role? :admin
    can :manage, :all
  else
    cannot :read, :admin
  end

我有可能做我想做的事吗?

4

1 回答 1

2

You can use a hack with route constraints:

class CanCanConstraint
  def initialize(action, resource)
    @resource, @action = resource, action
  end

  def matches?(request)
    # this will differ depending on your auth solution, for devise/warden:
    current_user = request.env['warden'].user        
    current_user && Ability.new(current_user).can?(@action, @resource) || false
  end
end

mount Trestle::Engine, at: '/admin', constraints: CanCanConstraint.new(:edit, :trestle)
match "/admin/*glob", to: "some_controller_when#trestle_not_authorized"

This way /admin only leads to trestle if user is authorized and has permission, otherwise first route will not match and you can handle request any way you like, for example with catch-all second route.

Depending on how you mount trestle - you may need to disable it's automount (config.automount = false in corresponding initializer)

于 2019-04-16T15:17:48.113 回答