Модель ролей и разрешений в базе данных
У меня есть пользовательская модель и множество других моделей в моем проекте, для создания системы 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 для роли.
Надеюсь, что эта помощь кому-нибудь достигнет этой точки.