feat(auth): auth layer decoupling, версия v1.3.24 в navbar и Help

This commit is contained in:
“Naeel”
2026-05-02 19:18:34 +04:00
parent 7ebdaf743c
commit 81367f7a5d
11 changed files with 476 additions and 286 deletions
+109
View File
@@ -0,0 +1,109 @@
# Логика авторизации — 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() — загрузить функции
```