Files
core/docs/auth/README.md

294 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🔐 Система аутентификации Discours Core
## 📚 Обзор
Модульная система аутентификации с JWT токенами, Redis-сессиями, OAuth интеграцией и RBAC авторизацией.
### 🎯 **Гибридный подход авторизации:**
**Основной сайт (стандартный подход):**
-**OAuth** (Google/GitHub/Yandex/VK) → Bearer токен в URL → localStorage
-**Email/Password** → Bearer токен в response → localStorage
-**GraphQL запросы**`Authorization: Bearer <token>`
-**Cross-origin совместимость** → работает везде
**Админка (максимальная безопасность):**
-**Email/Password** → httpOnly cookie (только для /panel)
-**GraphQL запросы**`credentials: 'include'`
-**Защита от XSS/CSRF** → httpOnly + SameSite cookies
-**OAuth отключен** → только email/password для админов
## 🚀 Быстрый старт
### Для разработчиков
```python
from auth.tokens.sessions import SessionTokenManager
from auth.utils import extract_token_from_request
# Проверка токена (автоматически из cookie или Bearer заголовка)
sessions = SessionTokenManager()
token = await extract_token_from_request(request)
payload = await sessions.verify_session(token)
if payload:
user_id = payload.get("user_id")
print(f"Пользователь авторизован: {user_id}")
```
### Для фронтенда
**Основной сайт (Bearer токены):**
```typescript
// Токен из localStorage
const token = localStorage.getItem('access_token');
const response = await fetch('/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}` // ✅ Bearer токен из localStorage
},
body: JSON.stringify({ query, variables })
});
```
**Админка (httpOnly cookies):**
```typescript
// Cookies отправляются автоматически
const response = await fetch('/graphql', {
method: 'POST',
credentials: 'include', // ✅ КРИТИЧНО: отправляет httpOnly cookies
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables })
});
```
### Redis ключи для поиска
```bash
# Сессии пользователей
session:{user_id}:{token} # Данные сессии (hash)
user_sessions:{user_id} # Список активных токенов (set)
# OAuth токены (для API интеграций)
oauth_access:{user_id}:{provider} # Access токен
oauth_refresh:{user_id}:{provider} # Refresh токен
```
## 📖 Документация
### 🏗️ Архитектура
- **[Обзор системы](system.md)** - Компоненты и менеджеры токенов
- **[Архитектура](architecture.md)** - Диаграммы и потоки данных
- **[Миграция](migration.md)** - Обновление с предыдущих версий
### 🔑 Аутентификация
- **[Управление сессиями](sessions.md)** - JWT токены и Redis хранение
- **[OAuth интеграция](oauth.md)** - Социальные провайдеры с httpOnly cookies
- **[Микросервисы](microservices.md)** - 🎯 **Интеграция с другими сервисами**
### 🛠️ Разработка
- **[API Reference](api.md)** - Методы и примеры кода
- **[Безопасность](security.md)** - Лучшие практики
- **[Тестирование](testing.md)** - Unit и E2E тесты
### 🔗 Связанные системы
- **[RBAC System](../rbac-system.md)** - Система ролей и разрешений
- **[Security System](../security.md)** - Управление паролями и email
- **[Redis Schema](../redis-schema.md)** - Схема данных и кеширование
## 🔄 OAuth Flow (правильный 2025)
### 1. 🚀 Инициация OAuth
```typescript
// Пользователь нажимает "Войти через Google"
const handleOAuthLogin = (provider: string) => {
// Сохраняем текущую страницу для возврата
localStorage.setItem('oauth_return_url', window.location.pathname);
// Редиректим на OAuth endpoint
window.location.href = `/oauth/${provider}/login`;
};
```
### 2. 🔄 OAuth Callback (бэкенд)
```python
# Google → /oauth/google/callback
# 1. Обменивает code на access_token
# 2. Получает профиль пользователя
# 3. Создает JWT сессию
# 4. Проверяет тип приложения:
# - Основной сайт: редиректит с токеном в URL
# - Админка: устанавливает httpOnly cookie
```
### 3. 🌐 Фронтенд финализация
**Основной сайт:**
```typescript
// Читаем токен из URL
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('access_token');
const error = urlParams.get('error');
if (error) {
console.error('OAuth error:', error);
navigate('/login');
} else if (token) {
// Сохраняем токен в localStorage
localStorage.setItem('access_token', token);
// Очищаем URL от токена
window.history.replaceState({}, '', window.location.pathname);
// Возвращаемся на сохраненную страницу
const returnUrl = localStorage.getItem('oauth_return_url') || '/';
localStorage.removeItem('oauth_return_url');
navigate(returnUrl);
}
```
**Админка:**
```typescript
// httpOnly cookie уже установлен
const error = urlParams.get('error');
if (error) {
console.error('OAuth error:', error);
navigate('/panel/login');
} else {
// Проверяем сессию (cookie отправится автоматически)
await auth.checkSession();
navigate('/panel');
}
```
## 🔍 Для микросервисов
### Подключение к Redis
```python
# Используйте тот же Redis connection pool
from storage.redis import redis
# Проверка сессии
async def check_user_session(token: str) -> dict | None:
sessions = SessionTokenManager()
return await sessions.verify_session(token)
# Массовая проверка токенов
from auth.tokens.batch import BatchTokenOperations
batch = BatchTokenOperations()
results = await batch.batch_validate_tokens(token_list)
```
### HTTP заголовки
```python
# Извлечение токена из запроса (cookie или Bearer)
from auth.utils import extract_token_from_request
token = await extract_token_from_request(request)
# Автоматически проверяет:
# 1. Authorization: Bearer <token>
# 2. Cookie: session_token=<token>
```
## 🎯 Основные компоненты
- **SessionTokenManager** - JWT сессии с Redis хранением + httpOnly cookies
- **OAuthTokenManager** - OAuth access/refresh токены для API интеграций
- **BatchTokenOperations** - Массовые операции с токенами
- **TokenMonitoring** - Мониторинг и статистика
- **AuthMiddleware** - HTTP middleware с поддержкой cookies
## ⚡ Производительность
- **Connection pooling** для Redis
- **Batch операции** для массовых действий (100-1000 токенов)
- **Pipeline использование** для атомарности
- **SCAN** вместо KEYS для безопасности
- **TTL** автоматическая очистка истекших токенов
- **httpOnly cookies** - автоматическая отправка браузером
## 🛡️ Безопасность (2025)
### Максимальная защита:
- **🚫 Защита от XSS**: httpOnly cookies недоступны JavaScript
- **🔒 Защита от CSRF**: SameSite=lax cookies
- **🛡️ Единообразие**: Все типы авторизации через cookies
- **📱 Автоматическая отправка**: Браузер сам включает cookies
### Миграция с Bearer токенов:
- ✅ OAuth теперь использует httpOnly cookies (вместо localStorage)
- ✅ Email/Password использует httpOnly cookies (вместо Bearer)
- ✅ Фронтенд: `credentials: 'include'` во всех запросах
- ✅ Middleware поддерживает оба подхода для совместимости
## 🔧 Настройка
### Environment Variables
```bash
# OAuth провайдеры
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
# Cookie настройки
SESSION_COOKIE_SECURE=true
SESSION_COOKIE_HTTPONLY=true
SESSION_COOKIE_SAMESITE=lax
SESSION_COOKIE_MAX_AGE=2592000 # 30 дней
# JWT
JWT_SECRET_KEY=your_jwt_secret_key
JWT_EXPIRATION_HOURS=720 # 30 дней
# Redis
REDIS_URL=redis://localhost:6379/0
```
### Быстрая проверка
```bash
# Проверка OAuth провайдеров
curl https://v3.discours.io/oauth/google
# Проверка сессии
curl -b "session_token=your_token" https://v3.discours.io/graphql \
-d '{"query":"query { getSession { success author { id } } }"}'
```
## 📊 Мониторинг
```python
from auth.tokens.monitoring import TokenMonitoring
monitoring = TokenMonitoring()
# Статистика токенов
stats = await monitoring.get_token_statistics()
print(f"Active sessions: {stats['session_tokens']}")
print(f"Memory usage: {stats['memory_usage'] / 1024 / 1024:.2f} MB")
# Health check
health = await monitoring.health_check()
if health["status"] == "healthy":
print("✅ Auth system is healthy")
```
## 🎯 Результат архитектуры 2025
**Гибридный подход - лучшее из двух миров:**
**Основной сайт (стандартный подход):**
-**OAuth**: Google/GitHub → Bearer токен в URL → localStorage → GraphQL запросы
-**Email/Password**: Login form → Bearer токен в response → localStorage → GraphQL запросы
-**Cross-origin совместимость**: Работает везде, включая мобильные приложения
-**Простота интеграции**: Стандартный Bearer токен подход
**Админка (максимальная безопасность):**
-**OAuth отключен**: Только email/password для админов
-**Email/Password**: Login form → httpOnly cookie → GraphQL запросы
-**Максимальная безопасность**: Защита от XSS и CSRF
- ✅ **Автоматическое управление**: Браузер сам отправляет cookies