Доступ и роли
Способы входа
Оба включаются и отключаются в настройках панели.
Telegram Login Widget — войти могут только те, чей ID перечислен в ADMINS. Требует домена, прописанного в BotFather, и HTTPS.
Telegram Mini App — если панель открыта внутри Telegram (кнопка «Открыть панель» в боте, команда /panel или Menu Button из BotFather), вход выполняется автоматически по подписанным initData — форма входа не показывается. Проверяется тот же список ADMINS, действуют те же политики метода входа и 2FA, что и у виджета. Отключается настройкой auth_telegram_webapp_enabled; если автовход не удался, панель молча показывает обычный экран входа.
Кнопка в боте появляется, когда задан публичный https-адрес панели — настройка «Общие → Публичный URL панели» (web_panel_public_url) или переменная APP_PUBLIC_URL.
Подписанные initData панель принимает только из фрагмента адреса и только внутри клиента Telegram — присланная в чате ссылка с #tgWebAppData=... не отравит вкладку администратора; сразу после чтения параметр вычищается из адреса. В полноэкранном режиме кнопки клиента Telegram лежат поверх страницы, поэтому шапка и боковая панель отступают на их высоту (--tg-content-safe-area-inset-* из вендоренного telegram-web-app.js).
Логин и пароль — аккаунты из базы (раздел «Администраторы») либо запасная пара WEB_ADMIN_LOGIN / WEB_ADMIN_PASSWORD из .env. К паролю можно включить 2FA по TOTP и вход по биометрии (WebAuthn).
Первый администратор создаётся формой регистрации при первом открытии панели. Если панель уже работает, а доступа нет — заводится через CLI:
docker exec -it <контейнер> python3 scripts/admin_cli.py create-superadmin --username adminРоли и права
RBAC гранулярный: право — это пара «ресурс, действие», например users.edit или nodes.restart. Роль собирается из прав, администратор получает роль.
Суперадмин получает все права автоматически, включая те, что объявляют плагины — при установке плагина его права появляются у суперадмина сами, а остальным ролям их выдают вручную.
Сессии
Браузер получает JWT в HttpOnly-cookie (rw_access, rw_refresh): JavaScript до них не дотянется, в localStorage они не попадают. Запросы, которые что-то меняют, дополнительно требуют заголовок X-CSRF-Token со значением cookie rw_csrf — защита double submit.
API-клиенты и мобильное приложение ходят обычным Authorization: Bearer <token>; токены возвращаются в теле ответов /auth/login, /auth/telegram и /auth/refresh. Для Bearer CSRF-заголовок не нужен.
WebSocket авторизуется через subprotocol (Sec-WebSocket-Protocol: access-token, <jwt>) или ту же cookie. Передача токена в query-строке (?token=) устарела и оставлена только для старых клиентов.
Время жизни токенов задаётся переменными WEB_JWT_EXPIRE_MINUTES (по умолчанию 30 минут) и WEB_JWT_REFRESH_HOURS (6 часов).
Ограничение доступа по сети
# Белый список: кто вообще может открыть панель
WEB_ALLOWED_IPS=1.2.3.4,10.0.0.0/24
# Кому верить в заголовках X-Forwarded-For
WEB_TRUSTED_PROXIES=172.18.0.0/16Про доверенные прокси
Если панель стоит за Cloudflare или чужим балансировщиком, а WEB_TRUSTED_PROXIES не заполнен, все запросы будут выглядеть пришедшими с адреса прокси. Это ломает и белый список, и защиту от перебора паролей, и разбор нарушений — везде окажется один и тот же адрес.
Внешние ключи
Для интеграций заводятся отдельные ключи с ограниченным набором прав — они не связаны с аккаунтами администраторов и не дают доступа в интерфейс. См. внешний API.
Аудит
Каждое действие администратора попадает в аудит-лог: кто, что, когда и с какого адреса. Автоматические действия системы (например, блокировка по нарушению) там тоже видны — с пометкой, что за ними не стоит человек.