Andrey Epifancev 1590302b79 AURORA-1690: названия ролей в блоке пользователя (role_details в /me)
GET /me дополнен role_details [{code, name}] (аддитивно), фронт показывает
названия ролей, при их отсутствии — коды. Требования внесены в спеки
authn-authz и consolidations-ui, change 184-user-role удалён.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 01:11:28 +04:00

7.9 KiB
Raw Blame History

authn-authz Specification

Purpose

Вход в ядро по JWT внешнего SSO (РАИСА): пользователь находится по email в app_user, его эффективные права — объединение прав его ролей из БД; любой защищённый маршрут объявляет требуемое право одной зависимостью. Для разработки — эмитент токенов за флагом.

Requirements

Requirement: Личность из JWT, пользователь из БД

Защищённый маршрут SHALL требовать заголовок Authorization: Bearer <jwt>. Ядро SHALL проверить подпись и срок токена настроенным проверяющим (dev HS256 при AUTH_DEV_ISSUER=true, иначе JWKS/публичный ключ по AUTH_*), извлечь email из claim AUTH_EMAIL_CLAIM (по умолчанию email) и найти app_user с этим email и is_active = true. Нет или невалидный токен → 401; пользователь не найден или неактивен → 403. Тело ошибки — {"detail": "<причина по-русски>"}. Отказы в аутентификации (401 при предъявленном токене, 403 «не найден / отключён / неоднозначен») и вход SHALL фиксироваться в журнале по требованию «События входа» спеки audit-trail (LOGIN_FAILED / LOGIN).

Scenario: Валидный токен активного пользователя

  • WHEN запрос несёт корректный токен с email = ka_rf@armka.local, и такой активный пользователь есть
  • THEN маршрут выполняется от имени этого app_user

Scenario: Пользователя нет в системе

  • WHEN токен валиден, но app_user с таким email отсутствует
  • THEN ответ 403, detail сообщает, что пользователь не зарегистрирован в АРМ

Scenario: Истёкший или подделанный токен

  • WHEN срок токена истёк или подпись не проходит
  • THEN ответ 401, тело {"detail": …}

Requirement: Эффективные права и зависимость require

effective_permissions(user) SHALL быть объединением permission.code по всем ролям пользователя (user_role → role_permission → permission); код роли в проверках MUST NOT использоваться. Зависимость require("<PERMISSION_CODE>") SHALL возвращать 403, если кода нет в эффективных правах, и MUST NOT обращаться к БД повторно в рамках одного запроса.

Scenario: Право есть

  • WHEN пользователь с ролью KA_GO вызывает маршрут с require("KFO_VERIFY")
  • THEN маршрут выполняется

Scenario: Права нет

  • WHEN пользователь с ролью EXPERT вызывает маршрут с require("DOCUMENT_EDIT")
  • THEN ответ 403, detail называет недостающее право

Scenario: Две роли

  • WHEN пользователю назначены роли KA_RF и CURATOR_GO
  • THEN его эффективные права — объединение прав обеих ролей без дубликатов

Requirement: GET /api/v1/me

Маршрут SHALL возвращать текущего пользователя: id, email, full_name, regional_office {id, name, is_head_office}, business_segment, roles (список code), role_details (те же активные роли списком {code, name}, name — role.name, порядок как в roles), permissions (отсортированный список code). Это единственный маршрут Среза 0, доступный любому аутентифицированному пользователю без require.

Scenario: Ответ для dev-пользователя

  • WHEN ka_rf@armka.local (роль KA_RF) запрашивает /api/v1/me
  • THEN ответ 200 содержит roles = ["KA_RF"], role_details с одним элементом {code: "KA_RF", name: <непустое название>} и permissions, равные правам KA_RF из матрицы §10

Requirement: Dev-эмитент токенов только в режиме разработки

При AUTH_DEV_ISSUER=true и DEBUG=true ядро SHALL предоставлять POST /api/v1/dev/token с телом {"email"}, возвращающий HS256 JWT (срок 8 часов) для существующего активного пользователя. При любом другом сочетании флагов маршрут MUST NOT существовать (404), а dev-проверяющий MUST NOT принимать токены.

Scenario: Получение dev-токена

  • WHEN AUTH_DEV_ISSUER=true, DEBUG=true и запрошен токен для admin@armka.local
  • THEN ответ 200 {access_token, token_type: "bearer"}, токен принимается /api/v1/me

Scenario: Прод-конфигурация

  • WHEN DEBUG=false
  • THEN POST /api/v1/dev/token возвращает 404, токен, подписанный dev-секретом, отвергается с 401

Requirement: Прод-конфигурация HTTP-поверхности

Документация API (/docs, /redoc, /openapi.json) SHALL существовать только при DEBUG=true; при DEBUG=false эти пути MUST отвечать 404 (не схемой и не страницей SPA) (OQ-66). CORS при DEBUG=true SHALL разрешать любой источник * без allow_credentials; при DEBUG=false — только источники из CORS_ORIGINS (JSON-список или строка через запятую), пустой список SHALL запрещать кросс-доменные запросы, allow_credentials — только для явного списка без * (OQ-65). Под /api/v1 SPA MUST NOT отвечать: неверный метод на существующий маршрут SHALL давать 405 с заголовком Allow и detail по-русски, несуществующий путь (в том числе dev-маршрут при выключенных флагах) — 404 (OQ-61); GET / SHALL отдавать index.html SPA без редиректа при любом ROOT_PATH (OQ-62).

Scenario: Документация в проде

  • WHEN DEBUG=false и запрошен /openapi.json
  • THEN ответ 404

Scenario: Кросс-доменный запрос в проде без настроенных источников

  • WHEN DEBUG=false, CORS_ORIGINS пуст, браузер шлёт preflight с Origin: https://other.example
  • THEN в ответе нет Access-Control-Allow-Origin

Scenario: Неверный метод

  • WHEN выполнен POST /api/v1/me
  • THEN ответ 405, заголовок Allow: GET

Scenario: Несуществующий путь API

  • WHEN выполнен GET /api/v1/no-such-route
  • THEN ответ 404, не index.html

Scenario: Корень приложения

  • WHEN при ROOT_PATH=/ выполнен GET /
  • THEN ответ 200 с index.html, без редиректа на //