213 lines
6.6 KiB
Markdown
213 lines
6.6 KiB
Markdown
|
# Security System
|
|||
|
|
|||
|
## Overview
|
|||
|
Система безопасности обеспечивает управление паролями и email адресами пользователей через специализированные GraphQL мутации с использованием Redis для хранения токенов.
|
|||
|
|
|||
|
## GraphQL API
|
|||
|
|
|||
|
### Мутации
|
|||
|
|
|||
|
#### updateSecurity
|
|||
|
Универсальная мутация для смены пароля и/или email пользователя с полной валидацией и безопасностью.
|
|||
|
|
|||
|
**Parameters:**
|
|||
|
- `email: String` - Новый email (опционально)
|
|||
|
- `old_password: String` - Текущий пароль (обязательно для любых изменений)
|
|||
|
- `new_password: String` - Новый пароль (опционально)
|
|||
|
|
|||
|
**Returns:**
|
|||
|
```typescript
|
|||
|
type SecurityUpdateResult {
|
|||
|
success: Boolean!
|
|||
|
error: String
|
|||
|
author: Author
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**Примеры использования:**
|
|||
|
|
|||
|
```graphql
|
|||
|
# Смена пароля
|
|||
|
mutation {
|
|||
|
updateSecurity(
|
|||
|
old_password: "current123"
|
|||
|
new_password: "newPassword456"
|
|||
|
) {
|
|||
|
success
|
|||
|
error
|
|||
|
author {
|
|||
|
id
|
|||
|
name
|
|||
|
email
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Смена email
|
|||
|
mutation {
|
|||
|
updateSecurity(
|
|||
|
email: "newemail@example.com"
|
|||
|
old_password: "current123"
|
|||
|
) {
|
|||
|
success
|
|||
|
error
|
|||
|
author {
|
|||
|
id
|
|||
|
name
|
|||
|
email
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Одновременная смена пароля и email
|
|||
|
mutation {
|
|||
|
updateSecurity(
|
|||
|
email: "newemail@example.com"
|
|||
|
old_password: "current123"
|
|||
|
new_password: "newPassword456"
|
|||
|
) {
|
|||
|
success
|
|||
|
error
|
|||
|
author {
|
|||
|
id
|
|||
|
name
|
|||
|
email
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### confirmEmailChange
|
|||
|
Подтверждение смены email по токену, полученному на новый email адрес.
|
|||
|
|
|||
|
**Parameters:**
|
|||
|
- `token: String!` - Токен подтверждения
|
|||
|
|
|||
|
**Returns:** `SecurityUpdateResult`
|
|||
|
|
|||
|
#### cancelEmailChange
|
|||
|
Отмена процесса смены email.
|
|||
|
|
|||
|
**Returns:** `SecurityUpdateResult`
|
|||
|
|
|||
|
### Валидация и Ошибки
|
|||
|
|
|||
|
```typescript
|
|||
|
const ERRORS = {
|
|||
|
NOT_AUTHENTICATED: "User not authenticated",
|
|||
|
INCORRECT_OLD_PASSWORD: "incorrect old password",
|
|||
|
PASSWORDS_NOT_MATCH: "New passwords do not match",
|
|||
|
EMAIL_ALREADY_EXISTS: "email already exists",
|
|||
|
INVALID_EMAIL: "Invalid email format",
|
|||
|
WEAK_PASSWORD: "Password too weak",
|
|||
|
SAME_PASSWORD: "New password must be different from current",
|
|||
|
VALIDATION_ERROR: "Validation failed",
|
|||
|
INVALID_TOKEN: "Invalid token",
|
|||
|
TOKEN_EXPIRED: "Token expired",
|
|||
|
NO_PENDING_EMAIL: "No pending email change"
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
## Логика смены email
|
|||
|
|
|||
|
1. **Инициация смены:**
|
|||
|
- Пользователь вызывает `updateSecurity` с новым email
|
|||
|
- Генерируется токен подтверждения `token_urlsafe(32)`
|
|||
|
- Данные смены email сохраняются в Redis с ключом `email_change:{user_id}`
|
|||
|
- Устанавливается автоматическое истечение токена (1 час)
|
|||
|
- Отправляется письмо на новый email с токеном
|
|||
|
|
|||
|
2. **Подтверждение:**
|
|||
|
- Пользователь получает письмо с токеном
|
|||
|
- Вызывает `confirmEmailChange` с токеном
|
|||
|
- Система проверяет токен и срок действия в Redis
|
|||
|
- Если токен валиден, email обновляется в базе данных
|
|||
|
- Данные смены email удаляются из Redis
|
|||
|
|
|||
|
3. **Отмена:**
|
|||
|
- Пользователь может отменить смену через `cancelEmailChange`
|
|||
|
- Данные смены email удаляются из Redis
|
|||
|
|
|||
|
## Redis Storage
|
|||
|
|
|||
|
### Хранение токенов смены email
|
|||
|
```json
|
|||
|
{
|
|||
|
"key": "email_change:{user_id}",
|
|||
|
"value": {
|
|||
|
"user_id": 123,
|
|||
|
"old_email": "old@example.com",
|
|||
|
"new_email": "new@example.com",
|
|||
|
"token": "random_token_32_chars",
|
|||
|
"expires_at": 1640995200
|
|||
|
},
|
|||
|
"ttl": 3600 // 1 час
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### Хранение OAuth токенов
|
|||
|
```json
|
|||
|
{
|
|||
|
"key": "oauth_access:{user_id}:{provider}",
|
|||
|
"value": {
|
|||
|
"token": "oauth_access_token",
|
|||
|
"provider": "google",
|
|||
|
"user_id": 123,
|
|||
|
"created_at": 1640995200,
|
|||
|
"expires_in": 3600,
|
|||
|
"scope": "profile email"
|
|||
|
},
|
|||
|
"ttl": 3600 // время из expires_in или 1 час по умолчанию
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
```json
|
|||
|
{
|
|||
|
"key": "oauth_refresh:{user_id}:{provider}",
|
|||
|
"value": {
|
|||
|
"token": "oauth_refresh_token",
|
|||
|
"provider": "google",
|
|||
|
"user_id": 123,
|
|||
|
"created_at": 1640995200
|
|||
|
},
|
|||
|
"ttl": 2592000 // 30 дней по умолчанию
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### Преимущества Redis хранения
|
|||
|
- **Автоматическое истечение**: TTL в Redis автоматически удаляет истекшие токены
|
|||
|
- **Производительность**: Быстрый доступ к данным токенов
|
|||
|
- **Масштабируемость**: Не нагружает основную базу данных
|
|||
|
- **Безопасность**: Токены не хранятся в основной БД
|
|||
|
- **Простота**: Не требует миграции схемы базы данных
|
|||
|
- **OAuth токены**: Централизованное управление токенами всех OAuth провайдеров
|
|||
|
|
|||
|
## Безопасность
|
|||
|
|
|||
|
### Требования к паролю
|
|||
|
- Минимум 8 символов
|
|||
|
- Не может совпадать с текущим паролем
|
|||
|
|
|||
|
### Аутентификация
|
|||
|
- Все операции требуют валидного токена аутентификации
|
|||
|
- Старый пароль обязателен для подтверждения личности
|
|||
|
|
|||
|
### Валидация email
|
|||
|
- Проверка формата email через регулярное выражение
|
|||
|
- Проверка уникальности email в системе
|
|||
|
- Защита от race conditions при смене email
|
|||
|
|
|||
|
### Токены безопасности
|
|||
|
- Генерация токенов через `secrets.token_urlsafe(32)`
|
|||
|
- Автоматическое истечение через 1 час
|
|||
|
- Удаление токенов после использования или отмены
|
|||
|
|
|||
|
## Database Schema
|
|||
|
|
|||
|
Система не требует изменений в схеме базы данных. Все токены и временные данные хранятся в Redis.
|
|||
|
|
|||
|
### Защищенные поля
|
|||
|
Следующие поля показываются только владельцу аккаунта:
|
|||
|
- `email`
|
|||
|
- `password`
|