inital commit

This commit is contained in:
root
2025-09-12 10:00:32 +05:00
parent f6bce5d120
commit b4455b7024
32 changed files with 1603 additions and 11 deletions
+248
View File
@@ -0,0 +1,248 @@
## Документация по аутентификации (Frontend)
### Обзор
JWT-аутентификация. Публичные и админские эндпоинты:
- POST `/api/auth/signin` — вход и выдача JWT + refreshToken
- POST `/api/auth/refresh` — обновление пары токенов (ротация)
- POST `/api/auth/logout` — выход (инвалидация refreshToken)
- POST `/api/admin/users` — создать пользователя (только `ROLE_ADMIN`)
Все запросы и ответы — JSON (`Content-Type: application/json`).
### Базовый URL
- Прод: укажите боевой домен/порт
- Dev локально: `http://localhost:8080`
### Переменные окружения (frontend)
- REACT_APP_API_URL или NEXT_PUBLIC_API_URL: базовый URL API
- Храните токен безопасно (HttpOnly cookie предпочтительно; если localStorage — учитывайте XSS риски)
## Создание пользователя (Admin)
### POST /api/admin/users
Требует: `Authorization: Bearer <admin_access_token>` и роль `ROLE_ADMIN`.
Запрос:
```json
{
"email": "user@example.com",
"password": "StrongPass123!"
}
```
Успех:
- 200 OK, пустой ответ
Ошибки:
- 400 Bad Request — невалидный email/пароль
- 401/403 — нет прав администратора
- 409 Conflict — email уже зарегистрирован
Пример (fetch):
```js
await fetch(`${API_URL}/api/admin/users`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${adminAccessToken}`,
},
body: JSON.stringify({ email, password }),
});
```
## Вход
### POST /api/auth/signin
Запрос:
```json
{
"email": "user@example.com",
"password": "StrongPass123!"
}
```
Успех:
- 200 OK
```json
{
"accessToken": "<JWT>",
"tokenType": "Bearer",
"refreshToken": "<refresh-token>"
}
```
Ошибки:
- 400/401 — неверные учетные данные
Пример (fetch):
```js
const res = await fetch(`${API_URL}/api/auth/signin`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
const { accessToken, refreshToken } = await res.json();
// Сохраните токен и используйте в Authorization заголовке
```
## Обновление токена (Refresh Token)
### Общая схема
- При успешном входе фронт получает пару токенов: `accessToken` (короткоживущий) и `refreshToken` (длинноживущий).
- `accessToken` используется в `Authorization: Bearer <JWT>`.
- Когда `accessToken` истекает (HTTP 401), фронт вызывает `/api/auth/refresh` с `refreshToken`, получает новую пару токенов (ротация) и повторяет запрос.
### Рекомендации по хранению
- `refreshToken` предпочтительно хранить в HttpOnly Secure SameSite cookie (сервер ставит Set-Cookie).
- Альтернатива (менее безопасная): хранить в памяти/secure storage и передавать в теле запроса.
### POST /api/auth/refresh
Запрос (вариант с телом):
```json
{
"refreshToken": "<refresh-token>"
}
```
Успех:
- 200 OK
```json
{
"accessToken": "<new-jwt>",
"tokenType": "Bearer",
"refreshToken": "<new-refresh-token>"
}
```
Ошибки:
- 400 — отсутствует/некорректный refreshToken
- 401 — просрочен/отозван/невалиден
Пример (fetch, с телом):
```js
const res = await fetch(`${API_URL}/api/auth/refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken }),
});
if (!res.ok) throw new Error('Refresh failed');
const { accessToken: newAccess, refreshToken: newRefresh } = await res.json();
```
Пример (cookie-стратегия):
```js
const res = await fetch(`${API_URL}/api/auth/refresh`, {
method: 'POST',
credentials: 'include',
});
const { accessToken } = await res.json();
```
### Ротация refreshToken
- При каждом refresh возвращайте новый `refreshToken` и инвалидируйте старый.
- На фронте заменяйте сохранённый refreshToken на новый.
### TTL (рекомендации)
- accessToken: 515 минут
- refreshToken: 730 дней
## Logout
- Если refreshToken хранится в cookie: `POST /api/auth/logout` — сервер чистит cookie и отмечает refreshToken как отозванный.
- Если в хранилище фронта — удалите локальные токены и по возможности вызовите `logout` для аннулирования на бэке.
## Авторизация последующих запросов
Передавайте JWT в заголовке:
```
Authorization: Bearer <JWT>
```
Пример защищенного вызова:
```js
await fetch(`${API_URL}/api/private/profile`, {
headers: { Authorization: `Bearer ${token}` },
});
```
## Формат ошибок (пример)
```json
{
"timestamp": "2025-09-11T12:34:56Z",
"status": 409,
"error": "Conflict",
"message": "Email already registered",
"path": "/api/auth/signup"
}
```
## Валидация на фронте
- Email: RFC-проверка и нормализация в lowercase
- Пароль: минимум 8 символов, цифра, буква, спецсимвол
- Обработайте статусы 400/401/409 и показывайте человекочитаемые сообщения
## Хранение токена
- Предпочтительно: HttpOnly Secure cookie, получаемое от бэкенда
- Альтернатива: `localStorage`/`sessionStorage` (учтите XSS; не вставляйте токен в DOM)
## Примеры cURL
Создание пользователя (admin):
```bash
curl -X POST "$API_URL/api/admin/users" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"StrongPass123!"}'
```
Вход:
```bash
curl -X POST "$API_URL/api/auth/signin" \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"StrongPass123!"}'
```
## Заметки по безопасности
- Не логируйте пароли и JWT
- Реализуйте logout (инвалидация на клиенте или список отозванных токенов на бэке, если нужно)
- Рекомендуется троттлинг/капча для /signin и создания пользователя
## Изменения в будущем
- Ротация refresh-токенов реализована; можно добавить список отозванных токенов
- Подтверждение email
- Сброс пароля через почту