简体   繁体   English

可以不可以授权管理员

[英]CanCanCan not authorizing admin

I'm using cancancan with rails_admin and devise gems. 我将cancancanrails_admin使用,并devise gems。 Even though the user has the role admin cancan shows the error You are not authorized to access this page. 即使用户具有admin角色也可以显示错误, You are not authorized to access this page. when trying to go to /admin route after logging in. 登录后尝试进入/admin路由时。

Here's my ability.rb 这是我的ability.rb

#models/ability.rb
class Ability
  include CanCan::Ability
  def initialize(user)
    can :read, :all                   # allow everyone to read everything
    if user && user.has_role?(:admin)
      can :access, :rails_admin       # only allow admin users to access Rails Admin
      can :dashboard                  # allow access to dashboard
      if user.role? :admin
        can :manage, :all             # allow superadmins to do anything
      end
    end
  end
end

Here's my user model 这是我的用户模型

#models/user.rb
class User < ActiveRecord::Base

    ROLES = %i[admin moderator banned]

    def roles=(roles)
        roles = [*roles].map { |r| r.to_sym }
        self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
    end

    def roles
        ROLES.reject do |r|
            ((roles_mask.to_i || 0) & 2**ROLES.index(r)).zero?
        end
    end

    def has_role?(role)
        roles.include?(role)
    end

    def role?(base_role)
        ROLES.index(base_role.to_s) <= ROLES.index(role)
    end

    def self.find_first_by_auth_conditions(warden_conditions)
        conditions = warden_conditions.dup
        if login = conditions.delete(:login)
            where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
        else
            if conditions[:username].nil?
                where(conditions).first
            else
                where(username: conditions[:username]).first
            end
        end
    end
    validate :validate_username

    def validate_username
        if User.where(email: username).exists?
            errors.add(:username, :invalid)
        end
    end
    validates_format_of :username, with: /^[a-zA-Z0-9_\.]*$/, :multiline => true
  # Include default devise modules. Others available are:
  # , :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :confirmable, :registerable,
  :recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]
  attr_accessor :login
  def login=(login)
    @login = login
  end

  def login
    @login || self.username || self.email
  end
end

Here's the rails_admin.rb 这是rails_admin.rb

#config/initializers/rails_admin.rb
RailsAdmin.config do |config|

  ## == Devise ==
   config.authenticate_with do
     warden.authenticate! scope: :user
   end
   config.current_user_method(&:current_user)

  ## == Cancan ==
   config.authorize_with :cancan

  config.actions do
    dashboard                     # mandatory
    index                         # mandatory
    new
    export
    bulk_delete
    show
    edit
    delete
    show_in_app

    ## With an audit adapter, you can add:
    # history_index
    # history_show
  end
end

Here's the user in my schema.rb 这是我的schema.rb的用户

create_table "users", force: :cascade do |t|
  t.string   "email",                  default: "", null: false
  t.string   "encrypted_password",     default: "", null: false
  t.string   "reset_password_token"
  t.datetime "reset_password_sent_at"
  t.datetime "remember_created_at"
  t.integer  "sign_in_count",          default: 0,  null: false
  t.datetime "current_sign_in_at"
  t.datetime "last_sign_in_at"
  t.string   "current_sign_in_ip"
  t.string   "last_sign_in_ip"
  t.string   "confirmation_token"
  t.datetime "confirmed_at"
  t.datetime "confirmation_sent_at"
  t.string   "unconfirmed_email"
  t.datetime "created_at",                          null: false
  t.datetime "updated_at",                          null: false
  t.string   "name"
  t.string   "username"
  t.string   "role"
  t.integer  "roles_mask"
end

add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
add_index "users", ["username"], name: "index_users_on_username", unique: true

I created a regular user and changed it's role attribute to admin using User.first.update_attribute :role, 'admin' 我创建了一个普通用户,并使用User.first.update_attribute :role, 'admin'将它的角色属性更改为admin User.first.update_attribute :role, 'admin'

I don't exactly understand the use of roles_mask . 我不完全了解roles_mask Do I need to use both role and roles_mask in my database? 我是否需要在数据库中同时使用roleroles_mask

  1. I don't fully understand what's going on in the User#roles but after arbitrarily assigning a role_mask of 0(the index of admin), I got an empty array. 我不完全了解User#roles但是在任意分配一个role_mask为0(admin的索引)之后,我得到了一个空数组。 I doubt that this is the behaviour you anticipated. 我怀疑这是您预期的行为。

  2. I see that the check for roles( has_role? ) uses the role_mask which you may not have assigned after the creation of your users. 我看到检查role( has_role? )使用的是您创建用户后可能尚未分配的role_mask。

To reduce some of these boilerplate code, I think it would be convenient to use ActiveRecord.enum . 为了减少其中的一些样板代码,我认为使用ActiveRecord.enum会很方便。

#models/user.rb
class User < AR::Base
  enum roles: %i[admin moderator banned]
end

note that to assign a default role, you could set that on your db or after_create . 请注意,要分配默认角色,可以在db或after_create

#models/ability.rb
class Ability
  include CanCan::Ability
  def initialize(user)
    can :read, :all                   # allow everyone to read everything
    if user && user.admin?
      can :access, :rails_admin       # only allow admin users to access Rails Admin
      can :dashboard                  # allow access to dashboard
      if user.admin?
        can :manage, :all             # allow superadmins to do anything
      end
    end
  end
end

You can also assign role to a particular user by user.admin! 您还可以通过user.admin!将角色分配给特定用户user.admin!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM