Есть ли способ построить динамическую авторизацию на основе ролей c в рельсах? - PullRequest
2 голосов
/ 07 февраля 2020

Я пытаюсь добиться авторизации на основе ролей в Rails.

Что нам требуется:

  1. Роли должны быть динамическими c, мы должны создавать, редактировать или удалять роли.
  2. Разрешения также должны быть динамическими c.

Выводы:

  1. Мы мы не можем использовать драгоценный камень pundit, потому что его политика устарела c, и мы не можем сделать его динамическим c.
  2. Мы можем использовать камень cancan, и мы можем использовать его динамически, но Я не понял, как это можно сделать? И как это работает с `базой данных?

Это мой первый проект по части авторизации. У нас есть рельсы как конец и vue. js как передний конец. Независимо от роли, в базе данных все данные должны быть сначала пустыми. Мы будем использовать seed для создания роли супер-администратора и предоставления всех разрешений. Супер-администратор будет создавать роли, редактировать роли, уничтожать роли, а также добавлять разрешения, редактировать и уничтожать разрешения в конечном итоге.

Если есть какой-либо другой полезный метод, пожалуйста, дайте мне знать.

Спасибо.

Ответы [ 4 ]

2 голосов
/ 07 февраля 2020

Pundit против CanCanCan

Ваши выводы о CanCanCan и Pundit просто бессмыслица. Ни один из них не является "stati c" или "Dynami c", и они имеют почти одинаковые функции. Архитектура и философия дизайна радикально отличаются.

CanCanCan (первоначально CanCan) написан как DSL, что было самой горячей вещью со времен нарезанного хлеба назад, когда Райан Бейтс создал CanCan 10 лет go. Он очень хорошо масштабируется и его легко освоить, но он становится очень уродливым, как только вы достигнете любого уровня сложности. Если что-либо, выполняющее «авторизацию Dynami c» в CanCanCan, станет кошмаром из-за его архитектуры. Класс способностей в CanCanCan - это бог всех объектов бога.

Pundit - это просто объектно-ориентированное программирование. В pundit ваши политики - это просто классы, которые принимают пользователя и ресурс в качестве аргументов инициализатора и отвечают на методы, такие как show?, create? et c. Изначально Pundit сложнее понять, но, поскольку он всего лишь OOP, вы можете адаптировать его так, как хотите. А поскольку ваши логины аутентификации c хранятся в отдельных объектах, они гораздо лучше масштабируются до сложности и придерживаются принципов SOLID.

Как настроить систему ролей Dynami c?

Это стандартная система ролей аля 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 позволяет вам go сделать шаг вперед и просто определить роли с классом в качестве ресурса. Например, user.add_role(:admin, Forum), который делает пользователя администратором на всех форумах.

Как мне создать систему разрешений?

Простая RBA C система может быть построенным как:

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

Хотя я сомневаюсь, что это действительно так просто в реальности.

1 голос
/ 07 февраля 2020

Если я правильно понимаю ваши требования, вы сможете использовать Pundit для достижения этой цели.

Насколько я понимаю,

  • Пользователи имеют роли
  • Пользователям могут быть назначены и отменены роли во время выполнения
  • Разрешения предоставляются либо ролям, либо пользователям напрямую.
  • Разрешения могут обновляться во время выполнения

Таким образом, вы можете иметь что-то вроде

class User
  has_many roles
  ...
end

class Role
  has_many permissions
  ...

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

И в своей политике вы можете проверить, имеет ли какая-либо из ролей пользователя необходимые разрешения.

class PostPolicy < ApplicationPolicy
  def update?
    user.roles.any? { |role| role.has_permission?('update_post') }
  end
end
0 голосов
/ 07 февраля 2020

Вам следует создать ассоциацию ролей has_many с пользователем или любой другой моделью, которую вы используете, а затем легко получить динамическую c авторизацию ролей.

0 голосов
/ 07 февраля 2020

Вы можете получить динамические c роли с pundit. pundit давайте определим простые Ruby объекты с методами, которые вызываются, чтобы определить, есть ли у пользователя разрешение на выполнение действия. Например:

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

Если вы хотите, чтобы у пользователя было несколько ролей, вы можете установить ассоциацию has_and_belongs_to_many: :roles для вашей модели User.

См .: https://guides.rubyonrails.org/association_basics.html#the -имеет-и-относится ко многим-ассоциации

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...