Add SSO
This commit is contained in:
282
СХЕМА_РАБОТЫ.md
Normal file
282
СХЕМА_РАБОТЫ.md
Normal file
@@ -0,0 +1,282 @@
|
||||
# 🔄 Схема работы OpenID Connect с ZITADEL
|
||||
|
||||
## Визуальная схема
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Пользователь│
|
||||
└──────┬──────┘
|
||||
│
|
||||
│ 1. Открывает страницу входа
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Frontend (React) │
|
||||
│ http://localhost:3000 │
|
||||
│ │
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ Форма входа │ │
|
||||
│ │ - Логин/Пароль │ │
|
||||
│ │ - Кнопка ZITADEL 🔐 │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
│ 2. Нажимает "Войти через ZITADEL"
|
||||
│ GET /api/auth/oidc/zitadel/login
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Backend (FastAPI) │
|
||||
│ http://localhost:8000 │
|
||||
│ │
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ OAuth Client │ │
|
||||
│ │ - Создаёт authorize URL │ │
|
||||
│ │ - Добавляет state, nonce │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
│ 3. Redirect на ZITADEL
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ ZITADEL │
|
||||
│ https://your-instance.zitadel.cloud│
|
||||
│ │
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ Страница входа │ │
|
||||
│ │ - Email/Username │ │
|
||||
│ │ - Password │ │
|
||||
│ │ - 2FA (опционально) │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
│ 4. Пользователь вводит данные
|
||||
│ 5. ZITADEL проверяет
|
||||
│ 6. Redirect с code
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Backend (FastAPI) │
|
||||
│ /api/auth/oidc/zitadel/callback │
|
||||
│ │
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ 7. Обмен code на token │ │
|
||||
│ │ POST /oauth/token │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ 8. Получение userinfo │ │
|
||||
│ │ - email │ │
|
||||
│ │ - name │ │
|
||||
│ │ - sub (user ID) │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ 9. Создание/обновление │ │
|
||||
│ │ пользователя в users.json │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ 10. Генерация JWT токена │ │
|
||||
│ │ для MC Panel │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
│ 11. Redirect на frontend
|
||||
│ ?token=xxx&username=yyy
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Frontend (React) │
|
||||
│ │
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ 12. Обработка callback │ │
|
||||
│ │ - Извлечение token │ │
|
||||
│ │ - Сохранение в localStorage│ │
|
||||
│ │ - Очистка URL │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ 13. Автоматический вход │ │
|
||||
│ │ - Загрузка данных │ │
|
||||
│ │ - Показ панели │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
│ 14. Пользователь в системе!
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ MC Panel Dashboard │
|
||||
│ - Серверы │
|
||||
│ - Тикеты │
|
||||
│ - Личный кабинет │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Детальный поток данных
|
||||
|
||||
### Шаг 1-2: Инициация входа
|
||||
```
|
||||
Пользователь → Frontend
|
||||
↓
|
||||
Frontend → Backend: GET /api/auth/oidc/zitadel/login
|
||||
↓
|
||||
Backend создаёт OAuth URL:
|
||||
- client_id
|
||||
- redirect_uri
|
||||
- scope: openid email profile
|
||||
- state (CSRF защита)
|
||||
- nonce (replay защита)
|
||||
```
|
||||
|
||||
### Шаг 3-6: Аутентификация в ZITADEL
|
||||
```
|
||||
Backend → ZITADEL: Redirect на /oauth/authorize
|
||||
↓
|
||||
ZITADEL показывает форму входа
|
||||
↓
|
||||
Пользователь вводит данные
|
||||
↓
|
||||
ZITADEL проверяет учётные данные
|
||||
↓
|
||||
ZITADEL → Backend: Redirect с code
|
||||
URL: /callback?code=xxx&state=yyy
|
||||
```
|
||||
|
||||
### Шаг 7-8: Получение данных
|
||||
```
|
||||
Backend → ZITADEL: POST /oauth/token
|
||||
Параметры:
|
||||
- code
|
||||
- client_id
|
||||
- client_secret
|
||||
- redirect_uri
|
||||
↓
|
||||
ZITADEL → Backend: access_token + id_token
|
||||
↓
|
||||
Backend извлекает userinfo:
|
||||
{
|
||||
"sub": "123456789012345678",
|
||||
"email": "user@example.com",
|
||||
"name": "John Doe",
|
||||
"picture": "https://..."
|
||||
}
|
||||
```
|
||||
|
||||
### Шаг 9-10: Создание пользователя
|
||||
```
|
||||
Backend проверяет users.json:
|
||||
- Ищет по oidc_id = "zitadel:123456789012345678"
|
||||
|
||||
Если найден:
|
||||
- Обновляет email, name, picture
|
||||
|
||||
Если не найден:
|
||||
- Создаёт нового пользователя
|
||||
- Генерирует username из email
|
||||
- Роль: "user"
|
||||
- Пустой пароль (OIDC пользователь)
|
||||
|
||||
Backend создаёт JWT токен:
|
||||
{
|
||||
"sub": "john_doe",
|
||||
"role": "user",
|
||||
"exp": 1234567890
|
||||
}
|
||||
```
|
||||
|
||||
### Шаг 11-14: Возврат в приложение
|
||||
```
|
||||
Backend → Frontend: Redirect
|
||||
URL: http://localhost:3000/?token=xxx&username=yyy
|
||||
↓
|
||||
Frontend (useEffect):
|
||||
- Извлекает token и username из URL
|
||||
- Сохраняет в localStorage
|
||||
- Очищает URL (history.replaceState)
|
||||
- Обновляет состояние (setToken, setUser)
|
||||
↓
|
||||
Frontend загружает данные:
|
||||
- GET /api/auth/me (проверка токена)
|
||||
- GET /api/servers (список серверов)
|
||||
↓
|
||||
Пользователь видит панель управления
|
||||
```
|
||||
|
||||
## Структура данных
|
||||
|
||||
### ZITADEL userinfo
|
||||
```json
|
||||
{
|
||||
"sub": "123456789012345678",
|
||||
"email": "user@example.com",
|
||||
"email_verified": true,
|
||||
"name": "John Doe",
|
||||
"given_name": "John",
|
||||
"family_name": "Doe",
|
||||
"picture": "https://avatar.url",
|
||||
"locale": "en"
|
||||
}
|
||||
```
|
||||
|
||||
### MC Panel user (users.json)
|
||||
```json
|
||||
{
|
||||
"john_doe": {
|
||||
"username": "john_doe",
|
||||
"password": "",
|
||||
"role": "user",
|
||||
"servers": [],
|
||||
"oidc_id": "zitadel:123456789012345678",
|
||||
"email": "user@example.com",
|
||||
"name": "John Doe",
|
||||
"picture": "https://avatar.url",
|
||||
"provider": "zitadel",
|
||||
"created_at": "2026-01-15T12:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### JWT токен (MC Panel)
|
||||
```json
|
||||
{
|
||||
"sub": "john_doe",
|
||||
"role": "user",
|
||||
"exp": 1737820800,
|
||||
"iat": 1737216000
|
||||
}
|
||||
```
|
||||
|
||||
## Безопасность
|
||||
|
||||
### Защита от атак
|
||||
|
||||
1. **CSRF (Cross-Site Request Forgery)**
|
||||
- State parameter проверяется
|
||||
- Случайное значение для каждого запроса
|
||||
|
||||
2. **Replay атаки**
|
||||
- Nonce в id_token
|
||||
- Одноразовое использование code
|
||||
|
||||
3. **Man-in-the-Middle**
|
||||
- HTTPS обязателен в продакшене
|
||||
- Проверка redirect_uri
|
||||
|
||||
4. **Token theft**
|
||||
- JWT с истечением (7 дней)
|
||||
- Хранение в localStorage (XSS защита нужна)
|
||||
|
||||
### Рекомендации для продакшена
|
||||
|
||||
```
|
||||
✓ Использовать HTTPS
|
||||
✓ Настроить CORS правильно
|
||||
✓ Добавить rate limiting
|
||||
✓ Логировать все входы
|
||||
✓ Мониторить подозрительную активность
|
||||
✓ Регулярно обновлять client_secret
|
||||
✓ Использовать refresh tokens
|
||||
```
|
||||
|
||||
## Готово! 🎉
|
||||
|
||||
Схема показывает полный цикл аутентификации через ZITADEL.
|
||||
|
||||
**Всё работает автоматически и безопасно!** 🔐
|
||||
Reference in New Issue
Block a user