@IsaevDev

Где лучше проверять права пользователя — модель/контроллер/%else%?

Допустим, у пользователя есть некий набор прав - редактирование, модерация и т.д.
Эти права влияют на поля, которые можно обновлять в модели или по которым можно искать.
Где проверять права пользователя в модели или в контроллере? Логика проверки довольно сложная и проверка в контроллере приведет к дублированию, если разные контроллеры цепляют один и тот же метод модели из разных ситуаций. Но в модели сложно учесть все сценарии.
Что посоветуете?
  • Вопрос задан
  • 296 просмотров
Решения вопроса 1
tiabc
@tiabc
Бизнес-партнер и консультант по технологиям
С системой прав всегда сложно работать и всегда нужно смотреть на конкретную реализацию и учитывать как она будет изменяться в будущем. В любом случае, я сейчас слегка включен в работу над подобной задачей в нашей компании и попробую дать какой-то полезный ответ.

В контроллере действительно проверять стоит только простые кейсы и недостаток проверки в контроллере как раз в том, что если, например, реализовали проверку в одном HTTP-контроллере и вдруг появляется CLI-контроллер, то хочется чтобы вызовы доменной логики были одинаковыми с любого места, включая валидацию. Соответственно, попробуем унести проверку доступа в другое место.

В модель все тоже уносить не хочется. Соблюдая принцип SoC и слоистости приложения, доменные модели в общем случае ничего не должны знать про пользователя, который производит над ними действие. Соответственно, есть предложение ввести некий третий компонент, который отвечает именно за проверку есть ли у пользователя доступ к определенному действию. Плюс уверен, что иногда захочется произвести какое-то действие над моделью без проверки прав.

Как вы написали, у вас есть некий набор прав и некие действия (модерация, редактирование) с некоторыми параметрами (поля для редактирования), которые можно производить над моделью. Соответственно, сформулируем какое-то решение. Оно может вам совершенно не подойти, это лишь простой вариант пальцем в небо, который иллюстрирует подход. Введем PolicyChecker с методами в духе canCreatePost(user, createPostRequest) bool, где каждый метод соответствует проверке конкретного действия с конкретными параметрами запроса у конкретного пользователя. Этот PolicyChecker все знает про авторизованных пользователей, про роли, группы и что бы то ни было у них есть, а если ему нужны дополнительные зависимости для проверки, они передаются ему в конструкторе или какой там у вас подход к управлению зависимостями.

Таким образом, в каждом контроллере вы на основе PolicyChecker'а сможете проверить, что данный пользователь авторизован на данное действие. Если появится еще один контроллер, то придется эту проверку писать заново и я считаю, что это правильно, т.е. PolicyChecker'ы могут быть опять же разные для разных контроллеров и правила проверки в них могут отличаться. Либо может быть необходимость вообще выполнить действие над моделью без авторизованного пользователя, как уже писал выше, и тогда никакие права можно и не проверять и просто забыть про PolicyChecker.

Конкретная реализация опять же зависит от вашего конкретного юз кейса и систему прав нужно хорошенько проектировать в связи с нуждами бизнеса потому что она имеет свойство лавинообразно разрастаться и приводить к сложностям в поддержке кода и вообще уязвимостям.

Надеюсь, мои рассуждения оказались вам полезны.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы