CanCanCan不授权管理员

时间:2016-06-14 22:44:06

标签: ruby-on-rails ruby-on-rails-4 devise rails-admin cancancan

我正在使用cancancanrails_admindevise宝石。即使用户具有角色admin cancan在登录后尝试转到You are not authorized to access this page.路线时也会显示错误/admin

这是我的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

这是我的用户模型

#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

这是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

以下是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

我创建了一个普通用户,并将其角色属性更改为admin User.first.update_attribute :role, 'admin'

我不完全理解roles_mask的用法。我是否需要在数据库中同时使用roleroles_mask

1 个答案:

答案 0 :(得分:0)

  1. 我不完全理解User#roles中发生了什么,但是在任意分配0(管理员索引)的role_mask之后,我得到了一个空数组。我怀疑这是你预期的行为。

  2. 我发现角色检查(has_role?)使用了在创建用户后可能未分配的role_mask。

  3. 为了减少一些样板代码,我认为使用ActiveRecord.enum会很方便。

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

    请注意,要分配默认角色,您可以在数据库或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
    

    您还可以通过user.admin!

    为特定用户分配角色
相关问题