154 lines
5.9 KiB
Python
154 lines
5.9 KiB
Python
"""
|
||
Middleware для проверки подтверждения email пользователя.
|
||
Блокирует все запросы, кроме связанных с подтверждением email.
|
||
"""
|
||
from django.http import JsonResponse
|
||
from django.utils.deprecation import MiddlewareMixin
|
||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
|
||
|
||
|
||
class EmailVerificationMiddleware(MiddlewareMixin):
|
||
"""
|
||
Middleware для проверки подтверждения email.
|
||
|
||
Разрешает доступ к следующим endpoints без подтверждения email:
|
||
- /api/users/auth/register/
|
||
- /api/users/auth/login/
|
||
- /api/users/auth/telegram/
|
||
- /api/users/auth/telegram/bot-info/
|
||
- /api/users/auth/token/refresh/
|
||
- /api/users/auth/verify-email/
|
||
- /api/users/auth/resend-verification/
|
||
- /api/users/auth/password-reset/
|
||
- /api/users/auth/password-reset-confirm/
|
||
- /api/users/auth/logout/
|
||
- /api/docs/ (Swagger документация)
|
||
- /api/schema/ (API схема)
|
||
"""
|
||
|
||
# Список путей, которые разрешены без подтверждения email
|
||
ALLOWED_PATHS = [
|
||
# Аутентификация и регистрация
|
||
'/api/auth/register/',
|
||
'/api/auth/login/',
|
||
'/api/auth/telegram/',
|
||
'/api/auth/telegram/bot-info/',
|
||
'/api/auth/token/refresh/',
|
||
'/api/auth/verify-email/',
|
||
'/api/auth/resend-verification/',
|
||
'/api/auth/change-password/',
|
||
'/api/auth/password-reset/',
|
||
'/api/auth/password-reset-confirm/',
|
||
'/api/auth/logout/',
|
||
# API документация
|
||
'/api/swagger/',
|
||
'/api/swagger.json',
|
||
'/api/swagger.yaml',
|
||
'/api/redoc/',
|
||
'/api/schema/',
|
||
# Статические файлы и медиа
|
||
'/static/',
|
||
'/media/',
|
||
# Admin панель
|
||
'/admin/',
|
||
# Health check
|
||
'/health/',
|
||
]
|
||
|
||
def process_request(self, request):
|
||
"""
|
||
Обработка запроса перед передачей в view.
|
||
"""
|
||
# Проверяем, является ли путь разрешенным
|
||
if self._is_allowed_path(request.path):
|
||
return None # Разрешаем запрос
|
||
|
||
# Проверяем, есть ли токен авторизации
|
||
if not self._has_auth_token(request):
|
||
return None # Если нет токена, пусть другие middleware обрабатывают
|
||
|
||
# Получаем пользователя из токена
|
||
user = self._get_user_from_token(request)
|
||
|
||
if user is None:
|
||
return None # Если не удалось получить пользователя, пусть другие middleware обрабатывают
|
||
|
||
# Проверяем подтверждение email
|
||
if not user.email_verified:
|
||
return JsonResponse(
|
||
{
|
||
'success': False,
|
||
'error': 'email_not_verified',
|
||
'message': 'Необходимо подтвердить email адрес для доступа к платформе',
|
||
'email': user.email,
|
||
},
|
||
status=403
|
||
)
|
||
|
||
return None # Разрешаем запрос
|
||
|
||
def _is_allowed_path(self, path: str) -> bool:
|
||
"""
|
||
Проверяет, является ли путь разрешенным.
|
||
"""
|
||
# Проверяем точное совпадение
|
||
if path in self.ALLOWED_PATHS:
|
||
return True
|
||
|
||
# Проверяем, начинается ли путь с разрешенного
|
||
for allowed_path in self.ALLOWED_PATHS:
|
||
if path.startswith(allowed_path):
|
||
return True
|
||
|
||
# Разрешаем доступ к статическим файлам и медиа
|
||
if path.startswith('/static/') or path.startswith('/media/'):
|
||
return True
|
||
|
||
# Разрешаем доступ к admin панели
|
||
if path.startswith('/admin/'):
|
||
return True
|
||
|
||
return False
|
||
|
||
def _has_auth_token(self, request) -> bool:
|
||
"""
|
||
Проверяет наличие токена авторизации в запросе.
|
||
"""
|
||
# Проверяем заголовок Authorization
|
||
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
|
||
if auth_header.startswith('Bearer '):
|
||
return True
|
||
|
||
# Проверяем токен в cookies (если используется)
|
||
if 'access_token' in request.COOKIES:
|
||
return True
|
||
|
||
return False
|
||
|
||
def _get_user_from_token(self, request):
|
||
"""
|
||
Получает пользователя из JWT токена.
|
||
"""
|
||
try:
|
||
# Используем JWTAuthentication для получения пользователя
|
||
jwt_auth = JWTAuthentication()
|
||
header = jwt_auth.get_header(request)
|
||
if header is None:
|
||
return None
|
||
|
||
raw_token = jwt_auth.get_raw_token(header)
|
||
if raw_token is None:
|
||
return None
|
||
|
||
validated_token = jwt_auth.get_validated_token(raw_token)
|
||
user = jwt_auth.get_user(validated_token)
|
||
return user
|
||
except (InvalidToken, TokenError, AttributeError, TypeError, ValueError):
|
||
# Если токен невалиден или отсутствует, возвращаем None
|
||
return None
|
||
except Exception:
|
||
# Для любых других ошибок также возвращаем None
|
||
return None
|
||
|