Corp/backend/api/middleware.py
2026-09-07 19:43:48 +03:00

66 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# backend/api/middleware.py
"""Legacy refresh middleware for server-rendered Django session clients.
The SPA sends Bearer tokens and refreshes them in its own HTTP transport. This
middleware only handles tokens stored under ``api.jwt_*`` in ``request.session``.
"""
from datetime import datetime, timedelta
import jwt
from django.conf import settings
from .client import SESSION_KEY_ACCESS, SESSION_KEY_REFRESH, get_api_client
class JWTRefreshMiddleware:
"""
Автоматически обновляет JWT access token, если он скоро истечёт.
Проверяет токен при каждом запросе и обновляет его, если осталось
меньше 5 минут до истечения (по умолчанию).
"""
def __init__(self, get_response):
self.get_response = get_response
# За сколько минут до истечения обновлять токен
self.refresh_threshold = timedelta(
minutes=int(getattr(settings, "JWT_REFRESH_THRESHOLD_MINUTES", 5))
)
def __call__(self, request):
# Проверяем только для авторизованных пользователей
if request.user.is_authenticated:
access_token = request.session.get(SESSION_KEY_ACCESS)
refresh_token = request.session.get(SESSION_KEY_REFRESH)
if access_token and refresh_token:
try:
# Декодируем токен БЕЗ проверки подписи (только для чтения
# exp)
decoded = jwt.decode(
access_token, options={"verify_signature": False}
)
exp = decoded.get("exp")
if exp:
# Время истечения токена
exp_time = datetime.fromtimestamp(exp)
# Текущее время
now = datetime.now()
# Оставшееся время
time_left = exp_time - now
# Если осталось меньше порога - обновляем
if time_left < self.refresh_threshold:
client = get_api_client(request)
client.refresh_tokens()
except (jwt.DecodeError, jwt.InvalidTokenError, ValueError):
# Если токен невалидный - ничего не делаем,
# ApiClient сам обработает при запросе
pass
response = self.get_response(request)
return response