Rails:有什么方法可以在 Rails 中构建基于动态角色的授权吗?

sus*_*sie 5 authorization roles ruby-on-rails role-base-authorization

我正在尝试在 Rails 中实现基于角色的授权。

我们的要求:

  1. 角色应该是动态的,我们应该能够创建、编辑或删除角色。
  2. 权限也应该是动态的。

发现:

  1. 我们不能使用punditgem,因为它的策略是静态的,我们不能使其动态。
  2. 我们可以使用cancangem,并且可以动态使用它,但我不知道如何做到这一点?它如何与“数据库”一起工作?

这是我在授权部分的第一个项目。我们以 Rails 作为后端,以 vue.js 作为前端。无论有什么角色,数据库上的所有数据首先都应该是空的。我们将使用种子创建超级管理员角色并授予所有权限。超级管理员会创建角色、编辑角色、销毁角色,最后还会添加权限、编辑权限、销毁权限。

如果还有其他有用的方法请告诉我。

谢谢。

max*_*max 4

庞迪特vs康康康

你关于 CanCanCan 和 Pundit 的结论纯属无稽之谈。它们都不是“静态”或“动态”的,并且它们具有几乎相同的功能。但架构和设计理念却截然不同。

CanCanCan(最初的 CanCan)是用 DSL 编写的,这是自 10 年前 Ryan Bates 创建 CanCan 以来最热门的东西。它的规模缩小得非常好,并且很容易学习,但一旦达到任何复杂程度,它就会变得非常丑陋。如果在 CanCanCan 中进行“动态授权”的话,由于其架构,这将是一场噩梦。CanCanCan中的能力类是所有神物中的神。

Pundit 就是面向对象编程。在 pundit 中,您的策略只是将用户和资源作为初始化参数并响应等方法的类。Pundit最初很难理解,但由于它只是 OOP,因此您可以根据需要对其进行定制show?create?由于您的身份验证逻辑存储在单独的对象中,因此它可以更好地扩展复杂性并遵守 SOLID 原则。

如何设置动态角色系统?

这是您的标准角色系统 ala 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

# rails g model user_roles user:belongs_to role:belongs_to   
class UserRole < ApplicationRecord
  belongs_to :user
  belongs_to :role
end

# rails g model role name:string resource:belongs_to:polymorphic
class Role < ApplicationRecord
  belongs_to :resource, polymorphic: true, optional: true
  has_many :user_roles
  has_many :users, through: :user_roles
end
Run Code Online (Sandbox Code Playgroud)

然后,您可以将角色范围限定为资源:

class Forum < ApplicationRecord
  has_many :roles, as: :resource
end
Run Code Online (Sandbox Code Playgroud)

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 

# rails g model permission name:string
class Permission < ApplicationRecord
end

# rails g model role_permission role:belongs_to permission:belongs_to
class RolePermission < ApplicationRecord
  belongs_to :role
  belongs_to :permission
end
Run Code Online (Sandbox Code Playgroud)

例如,您可以通过以下方式将“销毁”授予“版主” Forum.find(1)

role = Role.find_by!(name: 'moderator', resource: Forum.find(1))
role.permissions.create!(name: 'destroy')
role.has_permission?('destroy') # true
Run Code Online (Sandbox Code Playgroud)

尽管我怀疑现实中真的会这么简单。

  • 你必须自己跑腿。您提出的问题非常广泛,只能通过自己的研究才能回答。具体如何实现取决于领域。另外,我什至不知道从哪里开始回答“数据库如何工作?”之类的问题。如果您不知道这一点,那么您甚至无法开始执行此任务。 (2认同)