11 KiB
11 KiB
🔐 Система аутентификации 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 для админов
🚀 Быстрый старт
Для разработчиков
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 токены):
// Токен из 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):
// Cookies отправляются автоматически
const response = await fetch('/graphql', {
method: 'POST',
credentials: 'include', // ✅ КРИТИЧНО: отправляет httpOnly cookies
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables })
});
Redis ключи для поиска
# Сессии пользователей
session:{user_id}:{token} # Данные сессии (hash)
user_sessions:{user_id} # Список активных токенов (set)
# OAuth токены (для API интеграций)
oauth_access:{user_id}:{provider} # Access токен
oauth_refresh:{user_id}:{provider} # Refresh токен
📖 Документация
🏗️ Архитектура
- Обзор системы - Компоненты и менеджеры токенов
- Архитектура - Диаграммы и потоки данных
- Миграция - Обновление с предыдущих версий
🔑 Аутентификация
- Управление сессиями - JWT токены и Redis хранение
- OAuth интеграция - Социальные провайдеры с httpOnly cookies
- Микросервисы - 🎯 Интеграция с другими сервисами
🛠️ Разработка
- API Reference - Методы и примеры кода
- Безопасность - Лучшие практики
- Тестирование - Unit и E2E тесты
🔗 Связанные системы
- RBAC System - Система ролей и разрешений
- Security System - Управление паролями и email
- Redis Schema - Схема данных и кеширование
🔄 OAuth Flow (правильный 2025)
1. 🚀 Инициация OAuth
// Пользователь нажимает "Войти через Google"
const handleOAuthLogin = (provider: string) => {
// Сохраняем текущую страницу для возврата
localStorage.setItem('oauth_return_url', window.location.pathname);
// Редиректим на OAuth endpoint
window.location.href = `/oauth/${provider}/login`;
};
2. 🔄 OAuth Callback (бэкенд)
# Google → /oauth/google/callback
# 1. Обменивает code на access_token
# 2. Получает профиль пользователя
# 3. Создает JWT сессию
# 4. Проверяет тип приложения:
# - Основной сайт: редиректит с токеном в URL
# - Админка: устанавливает httpOnly cookie
3. 🌐 Фронтенд финализация
Основной сайт:
// Читаем токен из 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);
}
Админка:
// 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
# Используйте тот же 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 заголовки
# Извлечение токена из запроса (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
# 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
Быстрая проверка
# Проверка 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 } } }"}'
📊 Мониторинг
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