# Логика авторизации — Fission Console ## Что вводит пользователь В форме логина (`index.html`, overlay `#login-overlay`): - **Стенд** (`#l-env`): `dev` / `test` / `prod` - **Токен** (`#l-token`): JWT-токен из личного кабинета NUBES (Профиль → Токены) --- ## Фронтенд: `doLogin()` → `js/auth.js` 1. Берёт токен и стенд из формы 2. Делает `POST /console/api/auth` с `{ token, env }` в теле 3. Если ответ OK: - Сохраняет `auth_token` и `auth_env` в **localStorage** браузера - Вызывает `setUserAvatar(token)` — декодирует email из JWT payload и показывает в navbar - Скрывает overlay логина 4. Проверяет `GET /console/api/ns/status` — если namespace не готов, показывает overlay инициализации --- ## Бэкенд: `handleAuth` → `handlers.go:1022` 1. Принимает `POST /console/api/auth` 2. Валидирует токен через `resolveNamespaceForToken(token, env, testMode)` 3. Вызывает `EnsureUserNS` — гарантирует что K8s namespace + RBAC + quota существуют 4. Возвращает JSON: `{ ok: true, env: "test", namespace: "fission-..." }` --- ## Валидация токена: `validateDeckToken` → `server.go:279` **Deck API** — внешний сервис облачной платформы NUBES: ``` dev → https://deck-api-dev.ngcloud.ru/api/v1 test → https://deck-api-test.ngcloud.ru/api/v1 prod → https://deck-api.ngcloud.ru/api/v1 ``` Проверка: `GET {deckAPI}/index.cfm/instances` с заголовком `Authorization: Bearer {token}` - `401` → токен невалиден - Любой другой ответ → токен принят - Результат кэшируется на **5 минут** (`sync.Map`) --- ## Вычисление namespace: `namespaceFromJWT` → `auth.go:131` 1. JWT токен **не верифицируется по подписи** — Deck API уже это сделал 2. Декодируется payload (base64url) 3. Извлекается claim `"sub"` (идентификатор пользователя в облаке) 4. Namespace = `"fission-" + hex(SHA256(sub)[:8])` Пример: sub = `c3fce59430e41b0f...` → namespace `fission-c3fce59430e41b0f` --- ## Email в navbar: `setUserAvatar` / `jwtEmail` → `auth.js` - `jwtEmail(token)` — декодирует JWT payload на **фронтенде** (без обращения к серверу) - Берёт `payload.email` или `payload.sub` - Отображает в `#user-avatar` в левом верхнем углу (вместо синего кружка) --- ## Последующие запросы Каждый API-запрос от фронтенда включает заголовки: ``` X-Auth-Token: <токен из localStorage> X-Auth-Env: <стенд из localStorage> ``` `authMiddleware` (`auth.go`) снова валидирует токен (но из кэша — без нового HTTP-запроса к Deck API), вычисляет namespace и кладёт его в `context.Context` → все хендлеры работают в нужном namespace. --- ## Test-режим (FISSION_TEST_MODE=true) Вместо реального Deck API — проверяет заголовок `X-Test-Sub`. Если токен содержит `@` — трактуется как email и используется как sub для вычисления namespace. Используется в тестах и для live-тестирования без реальных токенов. --- ## Итого — схема ``` Пользователь вводит токен + стенд │ ▼ POST /console/api/auth │ ├─► validateDeckToken → Deck API ({env}.ngcloud.ru) → 200 = ОК │ ├─► namespaceFromJWT → decode JWT payload → claim "sub" → SHA256[:8] → "fission-XXXXXXXX" │ ├─► EnsureUserNS → K8s namespace + RBAC создаются если нет │ └─► { ok: true, namespace: "fission-..." } Фронтенд: ├─► localStorage.setItem('auth_token', token) ├─► localStorage.setItem('auth_env', env) ├─► jwtEmail(token) → email из JWT payload → показать в navbar └─► reloadAll() — загрузить функции ```