加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – Devise / Rolify / CanCan 2.0:防止用户改变

发布时间:2020-12-17 02:03:59 所属栏目:百科 来源:网络整理
导读:我使用Devise进行身份验证,使用Rolify进行角色管理,使用CanCan 2.0进行授权. 我试图允许:admin角色更改用户的角色,但禁止所有其他用户访问. 这是我尝试过但不起作用的: #ability.rbclass Ability include CanCan::Ability def initialize(user) if user.ha
我使用Devise进行身份验证,使用Rolify进行角色管理,使用CanCan 2.0进行授权.

我试图允许:admin角色更改用户的角色,但禁止所有其他用户访问.

这是我尝试过但不起作用的:

#ability.rb
class Ability
  include CanCan::Ability

  def initialize(user)
    if user.has_role? :admin
      can :access,:all
    elsif user.has_role? :moderator
      can [:index,:read,:update,:destroy],:users,:user_id => user.id
      cannot :access,[:role_ids]
    end
end

#application_controller.rb
...
rescue_from CanCan::Unauthorized do |exception|
    redirect_to root_url,:alert => exception.message
  end

我故意以我的用户形式离开了该协会:

#_form.html.erb
<%= simple_form_for @user do |f| %>
  <%= f.association :roles,as: :check_boxes %>
  <%#= f.association :roles,as: :check_boxes if can? :update,@user,:roles %>
  <%= f.button :submit %>
<% end %>

调节器

#users_controller.rb
class UsersController < ApplicationController

  before_filter :authenticate_user!
  load_and_authorize_resource

  def index
    @users = User.accessible_by(current_ability)
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])
  end

  def show
    @user = User.find(params[:id])
  end

  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])

    @user.update_without_password(params[:user])

    if successfully_updated
      redirect_to @user
    else
      render :action => "edit"
    end
  end
end

和模型:

#user.rb
    class User < ActiveRecord::Base
      rolify

      attr_accessible :role_ids
    ...

现在,如果具有以下角色的用户:moderator尝试更改另一个用户(或他自己的)角色,则会发生以下情况:

>抛出CanCan :: Unauthorized异常,并将用户重定向到root_url
>为用户更改角色

我很迷惑.如果发生异常,为什么还要进行更改?我可能做的事情非常错:)

我已经尝试根据users_controller.rb中的用户角色操作查询参数如果我在def更新后立即放置一个日志语句,这是我的输出:

2013-04-24 12:42:21 [4161] DEBUG    (0.1ms)  BEGIN
2013-04-24 12:42:21 [4161] DEBUG    (0.3ms)  INSERT INTO "users_roles" ("user_id","role_id") VALUES (5,1)
2013-04-24 12:42:21 [4161] DEBUG    (0.4ms)  COMMIT
2013-04-24 12:42:21 [4161] DEBUG   User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1  [["id","5"]]
2013-04-24 12:42:21 [4161] DEBUG {"username"=>"Blabla","email"=>"bla@bla.com","password"=>"","password_confirmation"=>"","approved"=>"1","role_ids"=>["1","2",""]}

我必须忽视一些事情……

解决方法

首先,你可能想要清理你的能力,因为目前似乎有些困惑.为了清楚起见,忽略其他所有内容,为密码修改指定自定义操作可能是个好主意.例如:

# ability.rb

def initialize(user)
  ...

  cannot :manage_roles,:user
  if user.has_role? :admin
    can :manage_roles,:user
  else
end

(你究竟想用其他规则来实现什么?目前如果看起来你只是让主持人阅读,编辑和删除自己,这是你想要的吗?)

您可能希望为任何无法对其执行任何操作的人隐藏或禁用表单的角色部分:

#_form.html.erb
<%= simple_form_for @user do |f| %>
  <%= f.association :roles,as: :check_boxes if can? :manage_roles,@user %>
  <%= f.button :submit %>
<% end %>

(注意,可以?只需要两个参数,即动作和对象/类.)

如果您想要更加安全,还可以在控制器中使用以下检查:

# users_controller.rb
def update
  @user = User.find(params[:id])

  user_params = params[:user]
  if cannot? :manage_roles,@user
    user_params.delete_if { |k,v| k.to_sym == :role_ids }
  end

  if @user.update_without_password(user_params)
    redirect_to @user
  else
    render :action => "edit"
  end
end

(你需要仔细检查从params散列中删除的正确密钥是什么,我假设它是:rol??e_ids基于你的attr_accessible,但我真的不太了解simple_form.)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读