Обзор — что делает этот механизм
В InfraGuard есть две плоскости аутентификации:
- Веб-консоль = сеансовый вход. Оператор входит по
login_id+password, иAuthControllerсоздаёт собственный сеанс. Дальше каждая страница консоли проходит через посредникinfr.auth(InfrAuth), который проверяет сеанс и при каждом запросе заново считывает из базы данных уровень, имя и язык пользователя, чтобы копия в сеансе оставалась актуальной. - Внешний API приёма данных = аутентификация по API-ключу без состояния. Когда внешнее приложение отправляет инциденты, отчёты о резервном копировании или результаты сканирования безопасности, оно аутентифицируется токеном API-ключа (
Authorization: Bearer …илиX-Infr-Api-Key) через посредникinfr.apikey, а не через сеанс. Ни сеанса, ни CSRF.
Ключевые особенности:
- Пересинхронизация сеанса — если администратор изменит уровень, имя или язык пользователя, изменение вступает в силу со следующего запроса, повторный вход не нужен.
- Контроль на уровне URL — скрыть пункты меню недостаточно. Группы маршрутов
/security,/backupи/adminзадают минимальный уровень прямо на URL посредством посредникаinfr.level:N. - Разрушительные действия = повторная проверка уровня + аудит — блокировка, восстановление, изменение настроек и т. п. защищены барьером уровня записи, записью в
infr_audit_logи подтверждением в интерфейсе.
Когда это применять
- Вы впервые входите в консоль или вас внезапно вернуло на
/login, и вы хотите понять причину. - Вы подключаете внешнее приложение на Laravel к API приёма инцидентов или к приёму отчётов о копировании и вам нужно знать, какой заголовок его аутентифицирует.
- Администратор изменил уровень, имя или язык, и вам нужно объяснить, почему повторный вход не требуется.
Устройство экрана
Экран входа (/login) — это одна простая карточка.
| Элемент | Описание |
|---|---|
| Бренд · слоган | Логотип Infra**Guard** + «Консоль эксплуатации, защиты и отказоустойчивости конвергентной инфраструктуры» |
| Логин | Поле login_id. autocomplete=username, фокус ставится автоматически |
| Пароль | Поле password + значок глаза для показа и скрытия |
| Баннер ошибки | При неудаче: «Указанные данные не совпадают с нашими записями.» |
Скрытое поле next |
Путь возврата после входа (должен начинаться с /) |
| Кнопка отправки | «Войти →» |
Форма входа несёт стандартный токен Blade
@csrf. Консоль защищена сеансом + CSRF и не запрашивает в интерфейсе отдельный bearer-токен.
Как пользоваться
Вход в систему
- Откройте
/login(если вы уже вошли, вас перенаправит на/). - Введите свои
Login IDиPassword.- Проверка:
login_id— не более 60 символов,password— от 4 до 120 символов.
- Проверка:
- Нажмите Войти. Сервер ищет учётную запись в
infr_userпоlogin_id+is_close=0и проверяет пароль. - При успехе сеанс пересоздаётся (
session()->regenerate()), и вас отправляют наnext(или на/).
Успешный вход заполняет следующие ключи сеанса:
| Ключ сеанса | Значение |
|---|---|
infr_user_id |
infr_user.id (источник истины для «аутентифицирован») |
infr_login_id |
Логин |
infr_user_level |
user_level (целое) — Уровень RBAC |
infr_name |
Отображаемое имя |
infr_lang |
Язык интерфейса (по умолчанию ko) |
Также в столбец last_log записывается текущее время.
Выход из системы
- Воспользуйтесь пунктом Выйти в выпадающем меню пользователя в верхней панели (или
POST /logout). - Сервер забывает
infr_user_id, аннулирует сеанс, пересоздаёт токен CSRF и перенаправляет на/login.
Время жизни сеанса и пересинхронизация при каждом запросе
Каждая страница консоли проходит через infr.auth (InfrAuth), который при каждом запросе:
- Заново загружает пользователя по
infr_user_idиз сеанса (горячий путь, минимум столбцов: id · login_id · name · email · user_level · role_id · team_id · lang · avatar · is_close). - Если учётной записи нет или у неё
is_close=1(отключена), уничтожает сеанс и перенаправляет на/login(либо возвращает JSON 401). - Перезаписывает
infr_user_level·infr_name·infr_langзначениями из базы данных — поэтому изменённые администратором уровень, имя или язык применяются со следующего запроса без повторного входа. - Кладёт модель пользователя в атрибут запроса
infr_userи задаёт язык интерфейса черезapp()->setLocale(). - Вызывает
OpsPolicy::markPresence(), чтобы отметить присутствие (экономный режим операционной политики использует это, чтобы решить, «работает ли сейчас кто-то в консоли», и регулировать сбор данных из базы — см. Операционная политика).
Время жизни сеанса определяется параметром SESSION_LIFETIME (по умолчанию 120 минут).
У входа в консоль нет отдельного флажка «запомнить меня». Сеанс держится указанное выше время; после его истечения нужно войти заново.
Аутентификация внешнего API приёма данных (bearer-ключ)
Когда внешнее приложение обращается к /api/v1/*, оно аутентифицируется API-ключом (без состояния — ни сеанса, ни CSRF).
| Способ | Пример заголовка |
|---|---|
| Bearer | Authorization: Bearer YOUR_KEY |
| Собственный заголовок | X-Infr-Api-Key: YOUR_KEY |
Как это работает:
- Сервер преобразует полученный токен в хеш и сравнивает его за постоянное время (сравнением за постоянное время) с
infr_api_key.key_hash(только активные ключи). Ключ в открытом виде никогда не сохраняется. - Ограничение 120 запросов в минуту на каждый ключ. При превышении возвращается
429 rate_limitedи заголовокRetry-After. - Каждый вызов обновляет
last_used_at·last_used_ip·use_count.
Основные конечные точки:
# Проверка связи / ключа
curl -sS https://infraguard.example.com/api/v1/ping \
-H "Authorization: Bearer YOUR_KEY"
# Автоматическая регистрация инцидента (с дедупликацией · source=pulse)
curl -sS -X POST https://infraguard.example.com/api/v1/incidents \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"NPE in checkout","fingerprint":"abc123","severity":"crit"}'
Выпускайте и отзывайте ключи, а также копируйте код интеграции в разделе Администрирование ▸ API-ключи (ключ в открытом виде показывается только один раз, при выпуске).
Step-up — защита разрушительных действий
Рискованные действия — блокировка, разблокировка, восстановление или изменение настроек — защищены не повторным вводом пароля, а тремя рубежами:
- Повторная проверка уровня — действия записи требуют как минимум уровня записи (2 и выше), а административные действия — уровня администратора (10), и это перепроверяется на сервере.
- Журнал аудита — значения до и после, а также исполнитель и IP записываются в журнал аудита (
infr_audit_log). - Подтверждение в интерфейсе — перед действием в интерфейсе появляется диалог подтверждения (step-up).
Источники данных
| Объект | Назначение |
|---|---|
infr_user |
Учётные записи операторов. Столбцы: login_id · password · user_level · name · email · lang · is_close · role_id · team_id · last_log · avatar |
| Хранилище сеансов (Redis) | Ключи сеанса, например infr_user_id (REDIS_PREFIX infr_) |
infr_api_key |
Хеш (key_hash) ключей API приёма данных · is_active · use_count · last_used_at/ip |
infr_audit_log |
Аудиторский след разрушительных действий и действий с безопасностью |
Столбец
infr_user.passwordникогда не попадает в журналы, URL или cookie. Открытое значение API-ключа показывается только при выпуске; в базе данных остаётся лишь хеш.
Права доступа
/login·/logout— доступны всем (гостям).- Вся консоль — требует действующего сеанса (
infr.auth). Без него запросы страниц перенаправляются на/login, а AJAX-запросы получают401 unauthenticated.
Барьеры на уровне URL (проверяются после входа):
| Область | Посредник | Минимальный уровень |
|---|---|---|
| Обычная консоль (Обзор · Инфраструктура · чтение Активов) | infr.auth |
Только вход (1) |
/security · /backup |
infr.level:2 |
2 |
/admin |
infr.level:10 |
10 |
/horizon · /pulse |
infr.admin |
10 |
| Раздел разработки | infr.dev |
9 |
Ступени уровней: demo=1 · staff=5 · admin=10. Полную политику см. в разделе Уровни доступа.
Устранение неполадок и частые вопросы
Я вхожу, но меня снова и снова возвращает на /login.
Cookie сеанса не сохраняется (несовпадение домена или SESSION_DOMAIN, либо cookie только для HTTPS отдаётся по HTTP), или учётной записи выставлено is_close=1 (отключена). Попросите администратора проверить состояние учётной записи.
Я вижу «Указанные данные не совпадают с нашими записями.»
Опечатка в login_id, неверный пароль или отключённая учётная запись (is_close=1). Из соображений безопасности сообщение не уточняет, что именно.
Учётная запись не может войти. Пароль может быть неверным или учётная запись отключена. Администратор сбрасывает пароль в разделе Пользователи и команды.
Я вхожу, но не могу открыть /admin.
Ваш уровень ниже 10. Раздел /admin защищён посредником infr.level:10, поэтому туда попадают только администраторы. Аналогично /security и /backup требуют уровня 2 и выше.
AJAX-запрос возвращает 401.
Сеанс консоли истёк. Обновите страницу и войдите заново. JSON-запросы получают {"error":"unauthenticated"} с кодом 401 вместо перенаправления.
Администратор повысил мой уровень, но это не применилось.
InfrAuth пересинхронизирует сеанс при каждом запросе, поэтому изменение применяется со следующего перехода — повторный вход не нужен. Обновите страницу, чтобы применить сразу.
Меню или интерфейс отображаются на неожиданном языке.
Язык интерфейса определяется полем infr_user.lang (ключ сеанса infr_lang) и пересинхронизируется при каждом запросе. Измените его в разделе Локализация.
API возвращает 401 invalid_api_key / 429 rate_limited.
Неактивный или неверно введённый ключ даёт 401; более 120 запросов в минуту дают 429 (+ Retry-After). Проверьте состояние ключа в разделе API-ключи и снизьте частоту обращений.
Смежные темы
- Уровни доступа —
user_level↔min_req, ступени demo/staff/admin - Роли и команды — область действия ролей и принадлежность команде
- Управление пользователями и командами — создание учётных записей, сброс паролей, отключение
- API-ключи — выпуск ключей API приёма данных и код интеграции
- Локализация — язык интерфейса и резервная локаль
- Журнал аудита — отслеживание разрушительных действий
