Files
core/docs/auth/system.md
Untone 14ff155789
All checks were successful
Deploy on push / deploy (push) Successful in 3m19s
config-fix
2025-09-30 21:48:29 +03:00

12 KiB
Raw Permalink Blame History

Система авторизации Discours Core

🎯 Обзор архитектуры

Модульная система авторизации с JWT токенами, Redis-сессиями и OAuth интеграцией. Построена на принципах разделения ответственности и высокой производительности.

auth/
├── tokens/                   # 🎯 Система управления токенами
│   ├── sessions.py           # JWT сессии с Redis
│   ├── verification.py       # Одноразовые токены
│   ├── oauth.py              # OAuth токены
│   ├── batch.py              # Массовые операции
│   ├── monitoring.py         # Мониторинг и статистика
│   ├── storage.py            # Фасад для совместимости
│   ├── base.py               # Базовые классы
│   └── types.py              # Типы и константы
├── middleware.py             # HTTP middleware
├── decorators.py             # GraphQL декораторы
├── oauth.py                  # OAuth провайдеры
├── identity.py               # Методы идентификации
├── jwtcodec.py               # JWT кодек
├── validations.py            # Валидация данных
├── credentials.py            # Креденшиалы
├── exceptions.py             # Исключения
└── utils.py                  # Утилиты

🎯 Система токенов

SessionTokenManager

Принцип работы:

  1. JWT токены с payload {user_id, username, iat, exp}
  2. Redis хранение для отзыва и управления жизненным циклом
  3. Поддержка множественных сессий на пользователя
  4. Автоматическое обновление last_activity при активности

Redis структура:

session:{user_id}:{token}     # hash с данными сессии
user_sessions:{user_id}       # set с активными токенами

Основные методы:

from auth.tokens.sessions import SessionTokenManager

sessions = SessionTokenManager()

# Создание сессии
token = await sessions.create_session(user_id, username=username)

# Проверка сессии
payload = await sessions.verify_session(token)

# Обновление сессии
new_token = await sessions.refresh_session(user_id, old_token)

# Отзыв сессии
await sessions.revoke_session_token(token)

# Получение всех сессий пользователя
user_sessions = await sessions.get_user_sessions(user_id)

Типы токенов

Тип TTL Назначение Менеджер
session 30 дней JWT сессии пользователей SessionTokenManager
verification 1 час Одноразовые токены подтверждения VerificationTokenManager
oauth_access 1 час OAuth access токены OAuthTokenManager
oauth_refresh 30 дней OAuth refresh токены OAuthTokenManager

Менеджеры токенов

1. SessionTokenManager - JWT сессии

from auth.tokens.sessions import SessionTokenManager

sessions = SessionTokenManager()

# Создание сессии
token = await sessions.create_session(
    user_id="123", 
    auth_data={"provider": "local"},
    username="john_doe",
    device_info={"ip": "192.168.1.1", "user_agent": "Mozilla/5.0"}
)

# Создание JWT токена сессии
token = await sessions.create_session_token(
    user_id="123",
    token_data={"username": "john_doe", "device_info": "..."}
)

# Проверка сессии (совместимость с TokenStorage)
payload = await sessions.verify_session(token)
# Возвращает: {"user_id": "123", "username": "john_doe", "iat": 1640995200, "exp": 1643587200}

# Валидация токена сессии
valid, data = await sessions.validate_session_token(token)

# Получение данных сессии
session_data = await sessions.get_session_data(token, user_id)

# Обновление сессии
new_token = await sessions.refresh_session(user_id, old_token, device_info)

# Отзыв сессии
await sessions.revoke_session_token(token)

# Отзыв всех сессий пользователя
revoked_count = await sessions.revoke_user_sessions(user_id)

# Получение всех сессий пользователя
user_sessions = await sessions.get_user_sessions(user_id)

2. VerificationTokenManager - Одноразовые токены

from auth.tokens.verification import VerificationTokenManager

verification = VerificationTokenManager()

# Создание токена подтверждения email
token = await verification.create_verification_token(
    user_id="123",
    verification_type="email_change",
    data={"new_email": "new@example.com"},
    ttl=3600  # 1 час
)

# Проверка токена
valid, data = await verification.validate_verification_token(token)

# Подтверждение (одноразовое использование)
confirmed_data = await verification.confirm_verification_token(token)

3. OAuthTokenManager - OAuth токены

from auth.tokens.oauth import OAuthTokenManager

oauth = OAuthTokenManager()

# Сохранение OAuth токенов
await oauth.store_oauth_tokens(
    user_id="123",
    provider="google",
    access_token="ya29.a0AfH6SM...",
    refresh_token="1//04...",
    expires_in=3600,
    additional_data={"scope": "read write"}
)

# Создание OAuth токена (внутренний метод)
token_key = await oauth._create_oauth_token(
    user_id="123",
    token_data={"token": "ya29.a0AfH6SM...", "provider": "google"},
    ttl=3600,
    provider="google",
    token_type="oauth_access"
)

# Получение access токена
access_data = await oauth.get_token(user_id, "google", "oauth_access")

# Оптимизированное получение OAuth данных
oauth_data = await oauth._get_oauth_data_optimized("oauth_access", "123", "google")

# Отзыв OAuth токенов
await oauth.revoke_oauth_tokens(user_id, "google")

# Оптимизированный отзыв токена
revoked = await oauth._revoke_oauth_token_optimized("oauth_access", "123", "google")

# Отзыв всех OAuth токенов пользователя
revoked_count = await oauth.revoke_user_oauth_tokens(user_id, "oauth_access")

4. BatchTokenOperations - Массовые операции

from auth.tokens.batch import BatchTokenOperations

batch = BatchTokenOperations()

# Массовая проверка токенов
tokens = ["token1", "token2", "token3"]
results = await batch.batch_validate_tokens(tokens)
# {"token1": True, "token2": False, "token3": True}

# Валидация батча токенов (внутренний метод)
batch_results = await batch._validate_token_batch(tokens)

# Безопасное декодирование токена
payload = await batch._safe_decode_token(token)

# Массовый отзыв токенов
revoked_count = await batch.batch_revoke_tokens(tokens)

# Отзыв батча токенов (внутренний метод)
batch_revoked = await batch._revoke_token_batch(tokens)

# Очистка истекших токенов
cleaned_count = await batch.cleanup_expired_tokens()

5. TokenMonitoring - Мониторинг

from auth.tokens.monitoring import TokenMonitoring

monitoring = TokenMonitoring()

# Статистика токенов
stats = await monitoring.get_token_statistics()
# {
#   "session_tokens": 150,
#   "verification_tokens": 5,
#   "oauth_access_tokens": 25,
#   "oauth_refresh_tokens": 25,
#   "memory_usage": 1048576
# }

# Подсчет ключей по паттерну (внутренний метод)
count = await monitoring._count_keys_by_pattern("session:*")

# Health check
health = await monitoring.health_check()
# {"status": "healthy", "redis_connected": True, "token_count": 205}

# Оптимизация памяти
optimization = await monitoring.optimize_memory_usage()
# {"cleaned_expired": 10, "memory_freed": 102400}

# Оптимизация структур данных (внутренний метод)
optimized = await monitoring._optimize_data_structures()

TokenStorage (Фасад для совместимости)

from auth.tokens.storage import TokenStorage

# Упрощенный API для основных операций
await TokenStorage.create_session(user_id, username=username)
await TokenStorage.verify_session(token)
await TokenStorage.refresh_session(user_id, old_token, device_info)
await TokenStorage.revoke_session(token)

🔧 Middleware и декораторы

AuthMiddleware

from auth.middleware import AuthMiddleware

# Автоматическая обработка токенов
middleware = AuthMiddleware()

# Извлечение токена из запроса
token = await extract_token_from_request(request)

# Проверка сессии
payload = await sessions.verify_session(token)

GraphQL декораторы

from auth.decorators import auth_required, permission_required

@auth_required
async def protected_resolver(info, **kwargs):
    """Требует авторизации"""
    user = info.context.get('user')
    return f"Hello, {user.username}!"

@permission_required("shout:create")
async def create_shout(info, input_data):
    """Требует права на создание публикаций"""
    pass

ORM модели

Author (Пользователь)

class Author:
    id: int
    email: str
    name: str
    slug: str
    password: Optional[str]      # bcrypt hash
    pic: Optional[str]           # URL аватара
    bio: Optional[str]
    email_verified: bool
    phone_verified: bool
    created_at: int
    updated_at: int
    last_seen: int
    
    # OAuth данные в JSON формате
    oauth: Optional[dict]        # {"google": {"id": "123", "email": "user@gmail.com"}}
    
    # Поля аутентификации
    failed_login_attempts: int
    account_locked_until: Optional[int]

OAuth данные

OAuth данные хранятся в JSON поле oauth модели Author:

# Формат oauth поля
{
    "google": {
        "id": "123456789",
        "email": "user@gmail.com",
        "name": "John Doe"
    },
    "github": {
        "id": "456789",
        "login": "johndoe",
        "email": "user@github.com"
    }
}

⚙️ Конфигурация

Переменные окружения

# JWT настройки
JWT_SECRET_KEY=your_super_secret_key
JWT_EXPIRATION_HOURS=720  # 30 дней

# Redis подключение
REDIS_URL=redis://localhost:6379/0

# 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
FACEBOOK_APP_ID=your_facebook_app_id
FACEBOOK_APP_SECRET=your_facebook_app_secret
VK_APP_ID=your_vk_app_id
VK_APP_SECRET=your_vk_app_secret
YANDEX_CLIENT_ID=your_yandex_client_id
YANDEX_CLIENT_SECRET=your_yandex_client_secret

# Session cookies
SESSION_COOKIE_NAME=session_token
SESSION_COOKIE_SECURE=true
SESSION_COOKIE_HTTPONLY=true
SESSION_COOKIE_SAMESITE=lax
SESSION_COOKIE_MAX_AGE=2592000  # 30 дней

# Frontend
FRONTEND_URL=https://yourdomain.com

Производительность

Оптимизации Redis

  • Pipeline операции для атомарности
  • Batch обработка токенов (100-1000 за раз)
  • SCAN вместо KEYS для безопасности
  • TTL автоматическая очистка

Кэширование

  • @lru_cache для часто используемых ключей
  • Connection pooling для Redis
  • JWT decode caching в middleware