# Спецификация 01: аутентификация владельца (AdminAuthService) Источники: Ф-9 (🛡 только владелец), tech-req 4.2 (PBKDF2 100k, префикс `pbkdf2$`), module_reqs разд. 2. ## 1. Формат хэша `Admin.PasswordHash` = `pbkdf2$100000$$`: PBKDF2-HMAC-SHA256, 100 000 итераций, соль 16 байт, вывод 32 байта, salt/hash — base64. Генерация (владельцу; python): ```bash python -c "import os,hashlib,base64;s=os.urandom(16);print('pbkdf2$100000$'+base64.b64encode(s).decode()+'$'+base64.b64encode(hashlib.pbkdf2_hmac('sha256',b'ПАРОЛЬ',s,100000)).decode())" ``` `AdminAuthService.HashPassword(password, salt?)` — тот же формат (используется тестами). ## 2. Сессии - `Login(login, password)`: сверка с `Admin.Login` (константное сравнение) и `Admin.PasswordHash` → валидно → токен `Base64Url(32 random bytes)`, словарь `token → expiresAt = UtcNow+8ч`; невалидно → `null` (эндпоинт отдаёт 401, без деталей); - `Validate(token)` → bool (просроченные удаляются лениво); - `Logout(token)` — удаление; - перезапуск сервера — словарь пуст (вход заново); - `Admin.Login` пуст в конфиге → консоль отключена: login всегда 401 (serve-валидацию не ломает — ключи опциональны); - 🛡2: токен/пароль/хэш не логируются и не возвращаются. ## 3. Эндпоинт и фильтр `POST /api/admin/login` body `{"login":"...","password":"..."}` → `200 {"token":"..."}` | `401 {"error":"unauthorized"}`. Rate: без ограничений в v1 (консоль за reverse-proxy, вопрос развёртывания). `AdminAuthFilter` (MVC-фильтр на контроллерах admin): заголовок `Authorization: Bearer `; нет/невалиден/просрочен → `401` `{"error":"unauthorized"}`. Контур `/api/admin/*` не проходит `ApiKeyMiddleware` (🛡1 — атлетские `X-Api-Key` там не действуют).