【问题标题】:CanCanCan not authorizing adminCanCanCan 未授权管理员
【发布时间】:2016-06-14 22:44:05
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:
    1. 我不完全理解 User#roles 中发生了什么,但是在任意分配 0 的角色掩码(管理员的索引)后,我得到了一个空数组。我怀疑这是您预期的行为。

    2. 我看到角色检查 (has_role?) 使用了您在创建用户后可能没有分配的角色掩码。

    为了减少这些样板代码,我认为使用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!为特定用户分配角色

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-13
      • 2012-07-12
      • 2017-07-27
      相关资源
      最近更新 更多