docs: архитектура авторизации облачного портала (из JWT)
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# Архитектура авторизации облачного портала
|
||||
|
||||
> Со слов пользователя, на основе JWT из localStorage
|
||||
|
||||
---
|
||||
|
||||
## Схема аутентификации
|
||||
|
||||
```
|
||||
Пользователь (браузер)
|
||||
│
|
||||
▼
|
||||
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.** У auth-api есть JWKS (`/.well-known/jwks.json`)? Или ключ статический? Как нашему сервису проверять подпись?
|
||||
|
||||
2. **isAdmin.** Флаг админа есть только в authData localStorage, но не в JWT. Как наш сервис узнает что пользователь — админ?
|
||||
- Вариант A: попросить добавить `isAdmin` в JWT
|
||||
- Вариант B: наш сервис ходит в auth-api за authData
|
||||
- Вариант C: смотреть на `ClientID == "WZ01112"` (как в ТЗ)
|
||||
|
||||
3. **Список компаний.** В JWT — только одна компания. В authData.profiles — массив. Для переключателя компаний в нашем UI — откуда брать список?
|
||||
- Вариант A: попросить добавить `profiles` в JWT
|
||||
- Вариант B: наш сервис ходит в auth-api
|
||||
|
||||
4. **Как наш сервис попадает в портал?** Как микро-фронтенд (SPA) или как отдельная страница с редиректом? Куда монтироваться?
|
||||
Reference in New Issue
Block a user