# Спецификация: middleware `X-Api-Key` (единица 2) ## Назначение Аутентификация запроса: ключ атлета → `athlete_id` (requirements Ф-8.5, Ф-7.2, 🛡 изоляция). Все эндпоинты, кроме `GET /health`, за middleware. ## Вход / выход - Вход: заголовок `X-Api-Key`. - Выход: `HttpContext.Items["athlete_id"] = int` (id из `src.athlete`). ## Логика 1. Нет заголовка → `401 {"error": "unauthorized"}`. 2. `hash = SHA256(значение)`; `athlete_select` по `p_api_key_hash = hash`. 3. Не найден или `is_blocked = true` → `401` (тело то же; различие «чужой/заблокирован» наружу не выдаётся). 4. Найден и не заблокирован → `Items["athlete_id"] = id`; вызов следующего обработчика. 5. Результат поиска кэшируется в пределах запроса (один запрос к БД на запрос). ## Тесты | # | Проверка | Ожидание | |---|---|---| | 1 | Запрос без `X-Api-Key` | 401 | | 2 | Неизвестный ключ | 401 | | 3 | Заблокированный ключ (`is_blocked = true`) | 401 | | 4 | Валидный ключ → `GET /api/v1/workouts` | 200, данные только этого атлета | | 5 | `GET /health` без ключа | 200 | ## Пример ``` GET /api/v1/workouts HTTP/1.1 X-Api-Key: ivan-key-1 ```