docs: актуализация (2026-05-30)

Deprecated (описывали состояние до рефакторинга):
  [DEPRECATED]-plan.md
  [DEPRECATED]-analysis-2026-05-30.md
  [DEPRECATED]-auth-architecture.md

Новые/обновлённые:
  architecture.md  — текущее устройство: стек, модули, auth-схема, env, маршруты
  plan.md          — только pending задачи (блокеры KK, деплой, Redis, пагинация)
  questions.md     — закрытые вопросы отмечены, открытые: KK creds + admin claim + /export IP
This commit is contained in:
“Naeel”
2026-05-30 14:42:52 +03:00
parent 9ad7eb9a8d
commit 608560eb64
7 changed files with 420 additions and 129 deletions
+95
View File
@@ -0,0 +1,95 @@
# Архитектура авторизации облачного портала
> ✅ ПРОВЕРЕНО: API успешно вызван через curl 2026-05-29.
---
## Схема аутентификации
```
Пользователь (браузер)
│
▼
Keycloak (keycloak.nubes.ru, realm=cloud)
│ Authorization Code Flow
│ client_id=deck.ngcloud.ru
│ scope=openid email
▼
auth-api.ngcloud.ru (СОБСТВЕННЫЙ сервис)
│ Создаёт свой JWT (issuer="auth-api")
│ Подпись: RS256 (RSA)
▼
deck.ngcloud.ru (портал)
│ Микро-фронтенды (SPA): dashboard, contracts, services, ...
│ JWT хранится в localStorage: authApiTokens.access_token
▼
IPWhiteList (наш сервис) ← будет встроен как микро-фронтенд в портал
```
## Важное
- JWT подписывает **не Keycloak**, а **auth-api**
- Issuer: `"auth-api"`, алгоритм: `RS256`
- Для валидации нужен публичный ключ auth-api (JWKS или статический)
---
## Структура JWT (access_token)
_Из localStorage → authApiTokens → access_token_
| Поле | Тип | Значение (пример) | Назначение |
|---|---|---|---|
| `iss` | string | `"auth-api"` | Кто выпустил токен |
| `sub` | string | `"0199e325-..."` | UUID пользователя |
| `iat` | number | `1780073927` | Выпущен (Unix time) |
| `exp` | number | `1780117127` | Истекает (~12 часов) |
| `jti` | string | `"4d8d7240-..."` | Уникальный ID токена |
| `ClientID` | string | `"WZ01325"` | ID **ТЕКУЩЕЙ** компании пользователя |
| `company_id` | string (UUID) | `"3e64aac6-..."` | UUID компании |
| `company_name` | string | `"Тест"` | Название компании |
| `email` | string | `"tazet@narod.ru"` | Email (для аудита) |
| `login` | string | `"tazet@narod.ru"` | Логин |
| `firstname` | string | `"Наиль"` | Имя |
| `lastname` | string | `"Тазетдинов"` | Фамилия |
| `token_type` | string | `"access"` | Тип токена |
## Что НЕ в JWT (отдельный authData в localStorage)
_Из localStorage → authData → v_
| Поле | Значение | Где используется |
|---|---|---|
| `userInfo.isAdmin` | `false` (boolean) | ⚠️ Признак администратора |
| `profiles[]` | Массив `{company_id, company_name, is_active_profile}` | Список всех компаний пользователя |
| `roles[]` | Массив `{role_id, role_name}` | Роли пользователя |
| `permissions.can_write` | `false` | Есть ли права на запись |
---
## Открытые вопросы (нужно уточнить с командой портала)
1. **Валидация JWT.** ✅ Выяснено: API gateway (`lk-api-gateway.ngcloud.ru`) сам валидирует JWT через auth-api. Нам достаточно передавать `Authorization: Bearer <JWT>`.
2. **isAdmin.** Флаг админа есть только в authData localStorage, но не в JWT. Как наш сервис узнает что пользователь — админ?
- Нужно уточнить: можно ли добавить `isAdmin` в JWT или получать через API gateway
3. **Список компаний.** В JWT — только одна компания. В authData.profiles — массив. Для переключателя компаний — откуда брать список?
4. **Монтирование в API gateway.** Наш сервис будет за `lk-api-gateway.ngcloud.ru` как отдельный route (например `/api/v1/whitelist/...`). Нужно уточнить процедуру добавления нового route.
---
## Как вызывать API (проверено curl'ом)
```bash
curl -H "Authorization: Bearer <JWT>" \
-H "Origin: https://deck.ngcloud.ru" \
-H "Cookie: __ddg1_=...; __ddg8_=...; __ddg9_=...; __ddg10_=..." \
"https://lk-api-gateway.ngcloud.ru/api/v1/..."
```
- **API Gateway:** `lk-api-gateway.ngcloud.ru` (не deck-api.ngcloud.ru!)
- **DDOS-Guard cookies ОБЯЗАТЕЛЬНЫ** (без них 403)
- **JWT issuer:** `auth-api`
- **Алгоритм:** RS256