你对CanCanCan和Pundit的结论纯属胡说。它们都不是“静态”或“动态”,并且它们几乎具有相同的功能。然而,它们的架构和设计哲学却截然不同。
CanCanCan(最初叫做CanCan)被写成DSL,这是自从十年前Ryan Bates创建CanCan以来最热门的东西。它可以很好地缩小规模,并且很容易学习,但一旦达到任何复杂程度,它会变得非常丑陋。如果在CanCanCan中进行“动态授权”,那么由于其架构,这将成为一场噩梦。CanCanCan中的“能力类”是所有上帝对象中的上帝。
Pundit只是面向对象编程。在Pundit中,您的策略只是接受用户和资源作为初始化参数并响应像
show?
,
create?
等方法的类。Pundit最初很难理解,但由于它只是OOP,因此可以根据您的需要进行定制。由于您的身份验证逻辑存储在单独的对象中,因此它可以更好地扩展到复杂性,并遵守SOLID原则。
如何设置动态角色系统?
这是您的标准角色系统,即
Rolify:
class User < ApplicationRecord
has_many :user_roles
has_many :roles, through: :user_roles
def has_role?(role, resource = nil)
roles.where({ name: role, resource: resource }.compact).exists?
end
def add_role(role, resource = nil)
role = Role.find_or_create_by!({ name: role, resource: resource }.compact)
roles << role
end
end
class UserRole < ApplicationRecord
belongs_to :user
belongs_to :role
end
class Role < ApplicationRecord
belongs_to :resource, polymorphic: true, optional: true
has_many :user_roles
has_many :users, through: :user_roles
end
然后您可以将角色限定于资源:
class Forum < ApplicationRecord
has_many :roles, as: :resource
end
Rolify让您更进一步,只需使用类作为资源定义角色。例如:user.add_role(:admin, Forum)
,这将使用户成为所有论坛的管理员。
如何创建权限系统?
一个简单的RBAC系统可以构建如下:
class Role < ApplicationRecord
has_many :role_permissions
has_many :permissions, through: :role_permissions
def has_permission?(permission)
permissions.where(name: permission).exists?
end
end
class Permission < ApplicationRecord
end
class RolePermission < ApplicationRecord
belongs_to :role
belongs_to :permission
end
例如,您可以通过以下方式将“destroy”授权给
Forum.find(1)
上的“moderators”:
role = Role.find_by!(name: 'moderator', resource: Forum.find(1))
role.permissions.create!(name: 'destroy')
role.has_permission?('destroy')
虽然我怀疑在现实中它并不会如此简单。