Модель ролей и разрешений в базе данных

У меня есть пользовательская модель и множество других моделей в моем проекте, для создания системы RBAC я реализовал роль и разрешение. пользователь has_and_belongs_to_many роли и роль has_and_belongs_to_many разрешения.

class Permission
  include Mongoid::Document
  field :ability, type: String

  has_and_belongs_to_many :roles
  belongs_to :permission_for, polymorphic: true, dependent: :destroy

  index({ability: 1,permission_for_id: 1},unique: true)
end

class Role
  include Mongoid::Document

  field :name, type: String

  has_and_belongs_to_many :permissions
  has_and_belongs_to_many :users
  belongs_to :role_for, polymorphic: true

  index({name: 1,role_for_id: 1},unique: true)
end

и в модели пользователя у меня есть:

Class User
  include Mongoid::Document
  .
  .
  .
  def able?(scope,model,action)
    # There must be something to load and check permissions
  end
end

Роль определена в области видимости (role_for) и разрешение, определенное в моделях в области действия роли (проект - это область действия, а задача - модель в этой области) с permission_for,

В пользовательской модели мне нужно получить данные из базы данных и проверить, может ли пользователь выполнить это действие, при большом количестве данных это занимает слишком много времени. able? Функция, которую я реализовал, проста: она просто загружает роль каждого пользователя и разрешение каждой роли, а затем проверяет, равна ли способность разрешения действию, а затем возвращает true или false!

Есть какой-нибудь драгоценный камень или код, делающий что-то подобное? и если нет, не могли бы вы дать мне совет, как реализовать роль и полномочия таким образом, с гораздо меньшей нагрузкой на базу данных?

Много много танков

Редактировать 1

Хорошо, я создал это отношение и смог использовать его в своих моделях, производительность при обычном использовании нормальная, но когда я хочу получить огромное количество данных, это очень медленно. Мне нужно кэшировать роли и разрешения в области видимости, как я могу это сделать? Есть ли какой-нибудь плагин для рельсов, который может сделать это для меня?

1 ответ

Наш продукт близок к запуску, и я реализовал это решение, но с небольшими изменениями:

Как я сделал RBAC:



  Проект <--- Роль <---> Разрешения ---> Задача
                 ^         (способность)
                 |          
                 |          
                 В          
               Пользователь (в состоянии?)               

Эта схема очень упрощенная версия окончательной реализации, но концепция та же

User.able?(model,ability) возвращает true, если объединение всех разрешений связанных ролей пользователя, связанных с моделью, имеет разрешение с возможностью.

    разрешение >> Просмотр Редактировать Удалить
    V Роль --------------------------------
     1 верно неверно неверно
     2 верно верно неверно
     3 ложь верно ложь
                 --------------------------------
   результат верно верно неверно

Если пользователь имеет роль 1,2,3, то пользователь может view , edit но не могу delete

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

 role.get_permissions
 # returns {modelID => ['view'], model2ID => ['view','edit']}

А затем объедините все эти хеши для пользователя и снова кешируйте этот новый хеш.

В каждом вызове able? метод класса пользователя я получаю этот хэш (из кэша или, если изменился, генерировать новый из базы данных) и задание выполнено:)

Нашей худшей проблемой в этом кэшировании было истечение срока действия кэша. Поэтому мы решили добавить новую функциональность в наш ORM (MongoID)

Добавление или удаление разрешений из роли обновит атрибут в ролевой модели (без обновления его временных меток)

Для роли пользователя на добавление / удаление / редактирование роли мы делаем это, а также для отношения проекта с ролью.

Но для разрешения задачи мы ничего не сделали, потому что разрешения никогда не изменятся (важна способность и ID).

Обновление отношения роли-разрешения не вызовет update_permission для роли.

Надеюсь, что эта помощь кому-нибудь достигнет этой точки.

Другие вопросы по тегам