我正在使用cancancan
与rails_admin
和devise
宝石。即使用户具有角色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
的用法。我是否需要在数据库中同时使用role
和roles_mask
?
答案 0 :(得分:0)
我不完全理解User#roles
中发生了什么,但是在任意分配0(管理员索引)的role_mask之后,我得到了一个空数组。我怀疑这是你预期的行为。
我发现角色检查(has_role?
)使用了在创建用户后可能未分配的role_mask。
为了减少一些样板代码,我认为使用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!