Роли и права

> Кратко. Права пользователя — это шаблон роли плюс отличия, которые администратор отметил галочками. Сервер проверяет права на каждом запросе сам, веб только прячет недоступные кнопки. Поверх прав действуют флаги сервера: без MUTATIONSENABLED данные нельзя менять никому, включая администратора.

Читаю как

Как выдавать роли и права в окне, описано на странице Пользователи. Здесь — модель прав и настройки сервера.

Матрица «вид объекта × действие»

Для каждой пары задаётся охват: нет, только свои или все.

Вид объекта Свойства Создание Перемещение и изломы Удаление
Участки ✓ ✓ ✓ ✓
Узлы ✓ ✓ ✓ ✓
Потребители ✓ ✓ ✓ ✓
Источники и насосные станции ✓ ✓ ✓ ✓
Оборудование ✓ ✓ — ✓
Режим узла (заданный напор, подпитка) ✓ — — —

Оборудование стоит на линии и отдельно не перемещается, режим узла только правится. Создание бывает «нет» или «все»: «создавать только свои» не имеет смысла.

«Только свои». Своими считаются объекты, которые пользователь создал в вебе. Авторство пишется в таблицу object_authorship базы города при сохранении правки. Строка карточки (оборудование, потребитель) своя, если свой её участок или узел. Объекты из десктопа и созданные до 20.10.2026 ничьи. С охватом «только свои» их нельзя ни править, ни удалять. Отказ называет чужие объекты: «Можно только со своими объектами, а это не ваши: …».

Общие права

Право Подпись в окне
calc_run Запуск расчётов
calc_save Сохранение и сравнение расчётов, направления пьезометра
export Выгрузки и отчёты
import Импорт сети
journals Журналы: ремонты, ПТС, акты, ТУ, привязки
refs Справочники и шаблоны карточек
audit_view Просмотр журнала действий
users_admin Управление пользователями
pii_view Персональные данные потребителей полностью (ФИО, телефоны, счета)

Шаблоны ролей

Роль Сеть Общие права
Просмотр (viewer) ничего выгрузки
Режимщик (calculator) свойства потребителей, источников, оборудования и режим узлов — все расчёты, сохранение расчётов, выгрузки
Оператор сети (operator) создание — все; свойства, перемещение, удаление — только свои выгрузки
Редактор (editor) свойства, создание, перемещение — все; удаление — только свои расчёты, сохранение, выгрузки, импорт, журналы, справочники, ПДн
Администратор (admin) всё — все все права

В UsersDB хранятся только отличия пользователя от шаблона (users.permissions, JSON): действующие права — шаблон роли плюс эти отличия. Их веб получает из /api/v1/auth/me.

Применить импорт сети может только администратор, даже если у другой роли есть право «Импорт сети»: с этим правом доступен лишь предпросмотр.

Защита от потери доступа: нельзя снять роль администратора с себя или заблокировать себя. Последнего активного администратора нельзя понизить или заблокировать, пока не настроена мастер-учётка.

Мастер-учётка

Учётная запись владельца вне UsersDB. Она нужна для первого входа на пустую базу пользователей и на случай, если все администраторы заблокированы.

  • Логин — MASTER_LOGIN (по умолчанию admin), пароль — хеш bcrypt в MASTER_PASSWORD_HASH. Пока хеш не задан, мастер-учётки нет.
  • Её логин занят: пользователя UsersDB с таким логином завести нельзя. Ей доступны все города, роль — администратор.
  • Из веба её нельзя удалить, заблокировать или сменить ей пароль: смена пароля в кабинете отвечает 409. Пароль меняют на сервере: записывают новый хеш в .env API и перезапускают API.
  • В токене мастер-учётки хранится отпечаток хеша. Новый хеш закрывает все её прежние сессии.
  • Хеш содержит символ $, поэтому в .env его пишут в одинарных кавычках.

Получить хеш можно функцией auth.hash_password из каталога API (venv\Scripts\python.exe, пароль вводится через getpass и в командную строку не попадает). Первого администратора UsersDB без мастер-учётки создаёт scripts/create_user.py <логин> --role admin. Пароль скрипт берёт из TGID_NEW_PASSWORD или спрашивает.

Флаги сервера

Флаг По умолчанию Что делает
AUTH_DISABLED true Проверки входа нет: каждый запрос — пользователь dev с ролью администратора. Управление пользователями отвечает 503 «…доступно только при AUTH_DISABLED=false», MCP принимает вызовы без токена. Только для стендов
AUTH_REQUIRED_GET false true — без токена закрыто всё, кроме /health, /docs, /openapi.json, /fragments, /russian-names, входа и настроек входа, /metrics, публичной карты отключений и встраиваемой карты. При false чтение данных сети, карточки и расчётные калькуляторы доступны без входа, а GeoServer пускает всех
STRICT_AUTH false true — API не стартует при AUTH_DISABLED=true, JWT_SECRET по умолчанию, DEV_LOGIN_ENABLED=true или AUTH_REQUIRED_GET=false
DEV_LOGIN_ENABLED false Вход с любым логином и любой ролью без пароля. На сервере с доступом извне — никогда
MUTATIONS_ENABLED false Без него — 503 на запись данных сети и журналов: карточки, групповая правка, журналы и привязки, наряды, обходы, отключения, телеметрия, водопровод, социальные объекты, сохранение расчёта. Расчёт запускается, если не пишет исходные данные; с сохранением нагрузок потребителей или дросселей (-save_po, -dross_yes) — 503
TOPOLOGY_MUTATIONS_ENABLED false Без него — 503 на правку состава сети: создание, перемещение, удаление, цепочки участков, импорт сети, перенос и слияние фрагментов, сценарии (создание, архив), перспективный сценарий. Нужен ещё MUTATIONS_ENABLED. Предпросмотр правок сети (dry_run) работает и без флага, а предпросмотр импорта сети и переноса фрагментов — нет: он пишет в откатываемой транзакции

Безопасный набор для сервера с доступом извне: AUTH_DISABLED=false, AUTH_REQUIRED_GET=true, STRICT_AUTH=true, DEV_LOGIN_ENABLED=false и собственный длинный JWT_SECRET.

MUTATIONS_ENABLED не блокирует то, что не меняет данные сети: управление пользователями, ключи встраивания, ключи API v2, ArcGIS и MCP, вебхуки, комментарии на карте, короткие ссылки, сохранённые стили слоёв и конфигурации трассировки. Эти действия проверяются только правами.

Текущие флаги видны без входа: GET /api/v1/auth/config и поле flags ответа /health. В вебе выключенная запись прячет или выключает кнопки (useMutationsEnabled). В подсказках части окон при этом показывается имя настройки, например «Запись выключена на сервере (MUTATIONS_ENABLED)».

Вход и сессии

  • Сессия — JWT на JWT_EXPIRE_MINUTES (по умолчанию 480 мин). Блокировка, смена роли и городов действуют на выданные токены через живую сверку с UsersDB (кеш USER_STATUS_TTL, 30 с).
  • После 5 неудачных входов на логин или 30 с одного адреса за 10 минут вход временно закрыт (429). Адрес берётся из CF-Connecting-IP, иначе из адреса соединения.
  • Удачные и неудачные входы, выходы и смена пароля пишутся в журнал действий.

Роли PostgreSQL

При AUTH_BACKEND=pg пользователи — роли PostgreSQL tgid_u_* с паролем, как в десктопе. Права на сеть они получают только из предметных прав (tgid_cap_network — свойства, tgid_cap_network_struct — состав сети и импорт). Журналы, справочники и ПДн — по правам pts, repairs, acts, corrosion, geo. Администратор получает всё. DB_ROLE_SWITCH=true ставит роль пользователя на каждое соединение: права проверяет ещё и сам PostgreSQL. Подробности — docs/pg-auth.md в репозитории API.

Для разработчика

  • Модель — permissions.py (KINDS, ACTIONS, GENERAL, ROLE_PRESETS, effective); в вебе шаблоны повторены в utils/permissions.ts. Новое право или роль меняют в обоих местах.
  • Новый маршрут записи — через require_permission(...) или проверку _guard / ensure_targets с охватом «свои», а не через require_roles. Плюс require_mutations_enabled() (или require_topology_mutations_enabled() для состава сети).
  • Флаги — auth.py (auth_disabled, mutations_enabled, auth_required_get, assert_production_auth_safe), обязательный вход — AuthRequiredGetMiddleware в main.py.
Хотите увидеть эту функцию на своих данных?Покажем ТГИД на демонстрации и ответим на вопросы инженеров.
Запросить демо