38 lines
1.5 KiB
Markdown
38 lines
1.5 KiB
Markdown
# Спецификация: 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
|
||
```
|