Files
core/docs/auth/README.md

11 KiB
Raw Permalink Blame History

🔐 Система аутентификации 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 токен

📖 Документация

🏗️ Архитектура

🔑 Аутентификация

🛠️ Разработка

🔗 Связанные системы

  • 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