Cancan 和 Devise 控制用户更新其他角色的能力
Cancan and Devise controlling user's ability to update other roles
我正在使用 cancan(can) 并在我的 Ruby Rails 应用程序中设计控制用户权限。我的用户模型有四个枚举角色:
class User < ApplicationRecord
enum role: {location: 0, basic: 1, admin: 2, moderator: 3}
我想做的是定义每个角色在 ability.rb
中可以控制的角色
我的 ability.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 进行新注册。
问题的最简单形式:
有没有办法做类似的事情->
cannot :sign_up, User.where(:role => 'moderator')
我可以指定哪些角色可以管理哪些其他角色?
我应该使用什么设计 controller/methods 来设置这些限制?
抱歉,如果这个问题已经得到解答,我通读了有关定义能力和设计的 wiki,但无法弄明白。
在此先致谢,我可以提供任何其他需要的代码片段来帮助您!
应用程序控制器: 我已经注释掉加载和授权并将它移到其他控制器的开头,因为它导致了不需要的行为(我不记得到底是什么)。
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
这个问题的答案很简单:
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
在我的 ability.rb
我正在使用 cancan(can) 并在我的 Ruby Rails 应用程序中设计控制用户权限。我的用户模型有四个枚举角色:
class User < ApplicationRecord
enum role: {location: 0, basic: 1, admin: 2, moderator: 3}
我想做的是定义每个角色在 ability.rb
中可以控制的角色我的 ability.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 进行新注册。
问题的最简单形式:
有没有办法做类似的事情->
cannot :sign_up, User.where(:role => 'moderator')
我可以指定哪些角色可以管理哪些其他角色?
我应该使用什么设计 controller/methods 来设置这些限制?
抱歉,如果这个问题已经得到解答,我通读了有关定义能力和设计的 wiki,但无法弄明白。
在此先致谢,我可以提供任何其他需要的代码片段来帮助您!
应用程序控制器: 我已经注释掉加载和授权并将它移到其他控制器的开头,因为它导致了不需要的行为(我不记得到底是什么)。
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
这个问题的答案很简单:
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
在我的 ability.rb