# Система авторизации 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 структура:** ```bash session:{user_id}:{token} # hash с данными сессии user_sessions:{user_id} # set с активными токенами ``` **Основные методы:** ```python 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 сессии ```python 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** - Одноразовые токены ```python 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 токены ```python 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** - Массовые операции ```python 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** - Мониторинг ```python 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 (Фасад для совместимости) ```python 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 ```python from auth.middleware import AuthMiddleware # Автоматическая обработка токенов middleware = AuthMiddleware() # Извлечение токена из запроса token = await extract_token_from_request(request) # Проверка сессии payload = await sessions.verify_session(token) ``` ### GraphQL декораторы ```python 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 (Пользователь) ```python 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`: ```python # Формат oauth поля { "google": { "id": "123456789", "email": "user@gmail.com", "name": "John Doe" }, "github": { "id": "456789", "login": "johndoe", "email": "user@github.com" } } ``` ## ⚙️ Конфигурация ### Переменные окружения ```bash # 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