【问题标题】:Cancan and Devise controlling user's ability to update other rolesCancan 和 Devise 控制用户更新其他角色的能力
【发布时间】:2018-07-18 14:32:58
【问题描述】:

我正在使用 cancan(can) 并设计来控制我的 Ruby on Rails 应用程序中的用户权限。我的用户模型有四个枚举角色:

class User < ApplicationRecord
    enum role: {location: 0, basic: 1, admin: 2, moderator: 3}

我要做的是在ability.rb中定义每个角色可以控制的角色

我的能力.rb 目前是这样的:

if user.basic?
    can :read, :all
    can :active_orders_index, Order
    can :search_orders, Order
    can :focused_show, Location
    can :mark_task_completed, Task 
    can :finish_task, Task
    cannot :create, User
elsif user.location?
    can :read, Location
    can :focused_show, Location
elsif user.admin?
    can :manage, :all    
elsif user.moderator?
    can :manage, :all
end

我在这个例子中想要做的就是阻止基本用户创建用户。在这种当前形式中,基本用户能够创建用户(cancan 由于未经授权而无法重定向),这不是预期的效果。我相信这是因为 :create 方法来自我的用户控制器,它没有被用来创建用户。我正在使用 Devise 的 new_user_registration 进行新注册。

问题的最简单形式:

  1. 有没有办法做类似的事情->

    cannot :sign_up, User.where(:role => 'moderator')
    

    以一种我可以指定哪些角色可以管理哪些其他角色的方式?

  2. 我应该使用什么设计控制器/方法来设置这些限制?

抱歉,如果这个问题已经得到解答,我阅读了关于定义能力和设计的 wiki,但无法弄清楚。

提前致谢,我可以提供任何其他需要的代码 sn-ps 以提供帮助!

应用程序控制器:我已将 load 和 authorize 注释掉并将其移至其他控制器的开头,因为它会导致不需要的行为(我不记得具体是什么)。

class ApplicationController < ActionController::Base
#load_and_authorize_resource

protect_from_forgery with: :exception

before_action :configure_permitted_parameters, if: :devise_controller?

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

def after_sign_in_path_for(resource)
  if resource.role == 'location'
    location_focused_path(Location.find_by(name: resource.username))
  elsif resource.role == 'basic'
    locations_path
  elsif resource.role == 'admin'
    active_orders_path
  elsif resource.role == 'moderator'
    active_orders_path
  end
end

protected

def configure_permitted_parameters
  added_atrs = [:role, :username, :email]
  devise_parameter_sanitizer.permit(:sign_up, keys: added_atrs)
  devise_parameter_sanitizer.permit(:account_update, keys: added_atrs)
end
end

注册控制器: 由 Devise 生成

class Users::RegistrationsController < Devise::RegistrationsController
#load_and_authorize_resource

skip_before_action :require_no_authentication, only: [:new, :create, :cancel]

# POST /resource
def create
    build_resource(sign_up_params)

    # yield resource if block_given?
    # ^ I removed this line otherwise identical to teh source code
    resource.save
    if resource.persisted?
       if resource.active_for_authentication?
           set_flash_message! :notice, :signed_up
           sign_up(resource_name, resource)
           respond_with resource, location: after_sign_up_path_for(resource)
       else
           set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
           expire_data_after_sign_in!
           respond_with resource, location: after_inactive_sign_up_path_for(resource)
       end
    else
       clean_up_passwords resource
       set_minimum_password_length
       respond_with resource
    end
 end

# Signs in a user on sign up. You can overwrite this method in your own
# RegistrationsController.
def sign_up(resource_name, resource)
    true
end

end

【问题讨论】:

  • 您能分享您的 application_controller 和设计 new_user_registration 控制器(以及任何其他相关控制器)吗?似乎没有进行授权调用;一个常见的配置是将check_authorization 添加到您的 application_controller 以强制对所有子控制器进行授权调用(请参阅ensure-authorization),然后在每个控制器内进行authorize_resource 调用(请参阅authorizing-resources
  • @andrew21 我添加了应用程序和注册控制器。我也没有调用 authorize_resource ,我曾经将它放在应用程序控制器中,但后来将它移到了每个相关的控制器中。最佳做法是修复它以使其位于应用程序控制器中吗?
  • 我认为 applicationcontroller 中的 check_authorization 是最佳实践,因为默认情况下它会强制所有继承控制器进行检查。 (减少安全错误的空间)然后您可以向每个控制器添加 authorize_resource 和/或 skip_authorization_check 以指定每个控制器的授权方式。
  • @andrew21 添加 check_authorization 为我尝试使用的任何 Devise 调用提供了“未初始化的常量 --------”,我尝试在注册控制器中使用 skip_authorization_check 但得到相同的错误:(跨度>

标签: ruby-on-rails ruby devise cancancan


【解决方案1】:

这个问题的答案很简单:

if user.present?
        if user.basic?
            can :read, :all
            can :active_orders_index, Order
            can :search_orders, Order
            can :focused_show, Location
            cannot :mark_task_completed, Task 
            can :finish_task, Task
            cannot :manage, User # ADDED LINE
        elsif user.location?
            can :read, Location, :name => user.username
            can :focused_show, Location, :name => user.username
            cannot :manage, User
        elsif user.admin?
            can :manage, :all
            cannot :manage, User, role: 3 # ADDED LINE
        elsif user.moderator?
            can :manage, :all
        end
 end

我的能力.rb

【讨论】:

    猜你喜欢
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    相关资源
    最近更新 更多