ruby-on-rails Rails:有没有什么方法可以在Rails中构建基于角色的动态授权?

t0ybt7op  于 2023-03-24  发布在  Ruby
关注(0)|答案(3)|浏览(172)

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

我们的要求:

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

调查结果:

1.我们不能使用pundit gem,因为它的策略是静态的,我们不能使它动态化。
1.我们可以使用cancan gem,我们可以动态地使用它,但我不知道它是如何做到的?以及它如何与`database一起工作?
这是我在授权部分的第一个项目。我们有rails作为后端,vue.js作为前端。无论有什么角色,数据库上的所有数据首先都应该是空的。我们将使用种子创建一个超级管理员角色并给予所有权限。超级管理员将创建角色,编辑角色,销毁角色,最终还将添加权限,编辑和销毁权限。
如果还有其他有用的方法,请告诉我。
谢谢。

eeq64g8w

eeq64g8w1#

Pundit vs CanCanCan

你对CanCanCan和Pundit的结论只是胡说八道。它们都不是“静态”或“动态”的,它们有着几乎相同的功能。尽管架构和设计哲学是完全不同的。
康康康CanCan(最初是CanCan)是一个DSL,它是自Ryan Bates 10年前创建CanCan以来最热门的东西。它可以很好地缩小规模,很容易学习,但一旦达到任何复杂程度,就会变得非常丑陋。如果在CanCanCan中做任何“动态授权”的话,由于其架构,这将是一场噩梦。CanCanCan中的能力职业是所有神物之神。
Pundit就是面向对象编程。在Pundit中,你的策略就是一些类,它们接受用户和资源作为初始化器参数,并响应像show?这样的方法。Pundit最初很难理解,但因为它只是OOP,所以你可以随心所欲地定制它。由于您的身份验证逻辑存储在单独的对象中,因此可以更好地扩展复杂性,并遵循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

然后,您可以将角色的范围扩展到资源:

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 

# 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

例如,您可以通过以下方式向Forum.find(1)上的“版主”授予“销毁”权限:

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

虽然我怀疑它在现实中真的会这么简单。

kh212irz

kh212irz2#

如果我对您的需求理解正确的话,您应该能够使用Pundit来实现这一点。
据我所知,

  • 用户具有角色
  • 可以在运行时为用户分配和取消分配角色
  • 权限直接授予角色或用户。
  • 可以在运行时更新权限

所以你可以有这样的东西,

class User
  has_many :user_role_mappings
  has_many :roles, through: :user_role_mappings
  has_many :permissions, through: :roles
  ...
end

class UserRoleMapping
  belongs_to :user
  belongs_to :role
end

class Role
  has_many :role_permission_mappings
  has_many :permissions, through :role_permission_mappings
  ...

  def has_permission?(permission)
    permissions.where(name: permission).exists?
  end
end

class RolePermissionMapping
  belongs_to :role
  belongs_to :permission
end

class Permission
  ...
end

在您的策略中,您可以检查用户的任何角色是否具有所需的权限。

class PostPolicy < ApplicationPolicy
  def update?
    user.roles.any? { |role| role.has_permission?('update_post') }
  end
end

编辑:
使用Map表,您可以从管理 Jmeter 板更新角色的权限和用户的角色。

vmdwslir

vmdwslir3#

您可以使用pundit实现动态角色。pundit让您使用方法定义普通Ruby对象,这些方法被调用以确定用户是否有权执行某个操作。例如:

class PostPolicy < ApplicationPolicy
  def update?
    user.has_role('admin')
  end
end

如果您希望一个用户拥有多个角色,您可以在User模型上设置一个has_and_belongs_to_many: :roles关联。
参见:https://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association

相关问题