Роли и права в приложении: как спроектировать без переделок
Роли «администратор» и «пользователь» быстро перестают работать, когда появляются филиалы, проекты и временные доступы. Разбираем модель прав, которая не превращает код и поддержку в набор исключений.

Роль «менеджер» почти никогда не описывает реальную границу доступа. В одном проекте менеджер должен видеть только своих клиентов, в другом — менять заказы, но не возвращать деньги, а в третьем — работать лишь с филиалом в Казани. Если заложить в код проверку названий ролей, первая же новая комбинация потребует исключения, миграции и ручного поиска по проекту. Ниже — практическая схема для веб-приложения: как разделить роли, разрешения и область действия так, чтобы модель можно было расширять без переписывания авторизации.
Сначала разделите три разных понятия
Главная ошибка — хранить в одном поле ответ на три вопроса: кто пользователь, что ему разрешено и над какими объектами действует право. Эти сущности нужно разделить.
- Пользователь — конкретная учётная запись.
- Роль — удобная группа полномочий, например «оператор поддержки».
- Разрешение — конкретное действие над конкретным типом ресурса: orders.read, orders.update, refunds.create.
- Область действия — набор объектов, к которым относится разрешение: организация, проект, филиал, команда или отдельный ресурс.
Роль должна собирать разрешения, а не быть единственным источником правил. Пользователь получает роль в определённой области: например, «бухгалтер» в организации A и «наблюдатель» в организации B.
Роль отвечает на вопрос «какой набор полномочий у человека», право — «что именно он может сделать», а область — «над какими объектами это разрешено».
Сноска. RBAC (Role-Based Access Control) — управление доступом через роли. В чистом RBAC разрешения назначаются ролям, а роли — пользователям. Ограничение по проекту, филиалу или владельцу объекта уже требует дополнительного контекста.
Выберите модель до того, как появятся исключения
Для большинства бизнес-приложений не нужно выбирать одну модель «навсегда». Практичный вариант — начать с RBAC для базовых полномочий и добавить проверки области действия на уровне запроса. Но сначала нужно понять, где будет храниться источник истины.
| Модель | Как принимает решение | Когда подходит | Цена |
|---|---|---|---|
| RBAC | Роль содержит набор разрешений | Стабильные должности и функции | Плохо описывает доступ к отдельному проекту или объекту |
| ACL | У каждого ресурса есть список пользователей и действий | Совместная работа с отдельными документами | Списки быстро разрастаются, аудит становится сложнее |
| ABAC | Правило учитывает атрибуты пользователя, ресурса и запроса | Сложные условия: регион, сумма, статус, время | Правила труднее тестировать и объяснять |
| Гибридная модель | Роль даёт право, контекст ограничивает область | CRM, SaaS, кабинеты организаций и проектов | Нужно отдельно контролировать роль и область |
Если пользователь может работать только с объектами своей организации, это не новая роль. Это ограничение области действия. Если право зависит от суммы платежа или статуса заказа, это уже контекстное правило, а не ещё одна роль.
Спроектируйте каталог разрешений
Начинайте не со списка должностей, а с действий продукта. Для каждого ресурса выпишите операции, которые реально существуют в интерфейсе и API. Не используйте расплывчатое право admin, если система может выразить более узкие операции.
- Составьте список ресурсов. Например: организации, пользователи, заказы, возвраты, отчёты и настройки биллинга. Проверка: у каждого защищённого endpoint или экрана есть понятный ресурс.
- Выпишите действия. Минимальный набор обычно включает просмотр, создание, изменение и удаление, но для заказа отдельно могут понадобиться подтверждение, отмена и возврат. Проверка: действие можно назвать одним глаголом без слова «полный доступ».
- Назначьте стабильные идентификаторы. Формат вроде orders.read или refunds.create лучше, чем русское название кнопки. Проверка: переименование пункта меню не меняет смысл разрешения.
- Свяжите разрешения с ролями. Роль «оператор поддержки» может читать заказы и менять контактные данные, но не создавать возврат. Проверка: для каждой роли можно получить полный список разрешений без чтения логики интерфейса.
- Добавьте область действия. Храните, в какой организации, проекте или филиале действует назначение роли. Проверка: один пользователь может иметь разные роли в двух областях без копирования учётной записи.
Список действий не обязан совпадать с HTTP-методами. Один endpoint может выполнять разные бизнес-операции, а одинаковое действие над разными ресурсами не означает одинаковое право.
Не превращайте роли в матрицу исключений
«Администратор», «старший администратор», «администратор без удаления», «администратор филиала без экспорта» — типичный путь к взрыву количества ролей. Такая схема выглядит простой, пока продукт маленький. Затем любое изменение требует понять, какая из похожих ролей уже получает доступ и не откроется ли лишняя функция.
Держите роли короткими и составными
Роль должна описывать устойчивую функцию, а не временную просьбу конкретного сотрудника. Составляйте её из атомарных разрешений. Если человеку нужно разовое право, лучше использовать отдельное назначение с датой окончания или согласованный временный доступ, а не создавать новую постоянную роль.
Разделяйте полномочия, которые нельзя совмещать
Для критических операций полезно разделить подготовку и подтверждение. Пользователь может создать платёж, но не подтверждать его. Это не только вопрос интерфейса: сервер должен проверять оба права независимо, иначе скрытая кнопка создаст лишь иллюзию защиты.
Не доверяйте данным из браузера
Роль, выбранная в интерфейсе, идентификатор организации и флаг «можно редактировать» приходят от клиента и не должны считаться доказательством доступа. Решение нужно принимать на сервере по текущему пользователю, назначению роли, области действия и объекту запроса.
Проверяйте не только действие, но и объект
Проверка «у пользователя есть orders.read» недостаточна. Она отвечает, можно ли читать заказы вообще, но не говорит, имеет ли пользователь отношение к заказу с конкретным идентификатором.
Правильная проверка состоит как минимум из двух частей:
- у пользователя есть нужное разрешение;
- запрошенный объект входит в область действия этого назначения.
Для владельца объекта это может быть условие «заказ принадлежит пользователю». Для сотрудника организации — «заказ связан с организацией, в которой назначена роль». Для руководителя филиала — «заказ относится к филиалу из доступного набора».
Особенно опасен шаблон, при котором сервер сначала загружает объект по переданному идентификатору, а проверку доступа выполняет позже или только в интерфейсе. В запросе к хранилищу лучше сразу ограничивать выборку областью пользователя. Тогда чужой объект не попадёт в результат даже при ошибке в последующей логике.
Что ломается первым
Проверки по названию роли
Условие вроде «если роль равна admin» жёстко связывает бизнес-логику с одной организацией прав. При добавлении второй административной роли часть функций легко забыть. Проверяйте разрешение, а не ярлык роли.
Скрытая кнопка вместо запрета на сервере
Отсутствие кнопки не закрывает API. Пользователь может повторить запрос из инструментов разработчика или отправить его напрямую. Каждая изменяющая операция должна иметь серверную проверку, даже если UI её не показывает.
Кэш без контекста пользователя
Кэширование результата проверки или списка объектов только по URL может отдать данные другого пользователя. В ключ должны входить все параметры, влияющие на доступ, либо такие ответы нельзя кэшировать общим слоем. При изменении ролей продумайте, как быстро устаревают уже сохранённые результаты.
Удалённые и переименованные разрешения
Если право убрали из кода, но оставили в базе, миграциях или старых назначениях, аудит становится ложным. Для разрешений нужны идентификаторы, описание владельца и процедура вывода из эксплуатации. Удаление права должно проходить как изменение схемы, а не как случайная правка строки.
Когда какая модель оправдана
Берите простой RBAC, если доступ определяется должностью и почти не зависит от объекта. Добавляйте область действия, если один пользователь работает в нескольких организациях, проектах или филиалах. Используйте ACL для точечного совместного доступа к небольшому числу документов, но не превращайте ACL в основной механизм для всех ресурсов.
Контекстные правила нужны, когда решение зависит от атрибутов: суммы операции, региона, статуса заказа или времени. Их следует держать в одном слое авторизации и покрывать тестами. Если условие разбросано по контроллерам, шаблонам и SQL-запросам, вы уже не сможете быстро ответить, почему конкретному пользователю разрешили операцию.
Минимальный чек-лист перед релизом
- Для каждого ресурса перечислены действия и нет неопределённого «полного доступа» без необходимости.
- Проверка выполняется на сервере для чтения и изменения данных.
- Разрешение проверяется вместе с областью действия объекта.
- Доступ по умолчанию запрещён, если правило не найдено.
- Есть тесты на разрешённый доступ, отказ и попытку обратиться к чужому объекту.
- Изменение роли попадает в журнал аудита с пользователем, временем и причиной.
- Предусмотрены отзыв роли, блокировка пользователя и истечение временного доступа.
- API и фоновые задачи используют тот же слой проверок, что и веб-интерфейс.
Что сделать дальше
Возьмите один критичный сценарий — например, возврат заказа — и нарисуйте путь решения от пользователя до конкретного объекта. Отметьте роль, разрешение, область и все контекстные условия. Затем добавьте негативные тесты: чужая организация, удалённая роль, устаревшая сессия и прямой запрос к API.
После этого настройте аудит отказов доступа и посмотрите на него в тестовой среде. В проде важнее всего не количество ролей, а число необъяснимых разрешений, частота отказов и время отзыва доступа после изменения назначения. Инвалидацию сессий и кэшей прав стоит рассматривать отдельно: она зависит от фреймворка, хранилища и архитектуры авторизации.
Защитник прав потребителей: Досудебные претензии на возврат товара со ссылками на ЗоЗПП.
Спросить за 15 ₽Источники: OWASP Authorization Cheat Sheet, NIST Role-Based Access Control
Частые вопросы
Нужно ли делать отдельную роль для каждого исключения?
Достаточно ли скрыть запрещённую кнопку в интерфейсе?
Как запретить пользователю видеть чужую организацию?
Что делать, если права изменились, а у пользователя осталась старая сессия?
Когда RBAC уже недостаточно?
Как тестировать модель прав?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.