feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
This commit is contained in:
95
app/auth/middleware.py
Normal file
95
app/auth/middleware.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""
|
||||
Middleware для проверки аутентификации
|
||||
Автор: Сергей Антропов
|
||||
Сайт: https://devops.org.ru
|
||||
"""
|
||||
|
||||
from fastapi import Request, HTTPException, status
|
||||
from fastapi.responses import RedirectResponse
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from app.auth.security import decode_access_token
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Публичные пути, не требующие аутентификации
|
||||
PUBLIC_PATHS = [
|
||||
"/login",
|
||||
"/api/v1/auth/login",
|
||||
"/logout",
|
||||
"/api/v1/auth/logout",
|
||||
"/health",
|
||||
"/static",
|
||||
"/api/docs",
|
||||
"/api/redoc",
|
||||
"/openapi.json",
|
||||
"/api/v1/stats", # Статистика доступна без аутентификации
|
||||
"/api/v1/dockerfiles/build-logs/webhook", # Webhook для получения логов от builder
|
||||
"/api/v1/dockerfiles/build-logs/recent" # Получение последних логов сборки (может использоваться на странице сборки)
|
||||
]
|
||||
|
||||
|
||||
class AuthMiddleware(BaseHTTPMiddleware):
|
||||
"""Middleware для проверки аутентификации"""
|
||||
|
||||
async def dispatch(self, request: Request, call_next):
|
||||
path = request.url.path
|
||||
|
||||
# Пропускаем публичные пути (проверяем точное совпадение или начало пути)
|
||||
is_public = False
|
||||
for public_path in PUBLIC_PATHS:
|
||||
if path == public_path or path.startswith(public_path + "/") or path.startswith(public_path):
|
||||
is_public = True
|
||||
break
|
||||
|
||||
if is_public:
|
||||
return await call_next(request)
|
||||
|
||||
# Проверка токена из cookie или заголовка
|
||||
token = None
|
||||
|
||||
# Проверяем cookie
|
||||
if request.cookies and "access_token" in request.cookies:
|
||||
token = request.cookies.get("access_token")
|
||||
# Проверяем заголовок Authorization
|
||||
elif "authorization" in request.headers:
|
||||
auth_header = request.headers.get("authorization", "")
|
||||
if auth_header and auth_header.startswith("Bearer "):
|
||||
token = auth_header.replace("Bearer ", "")
|
||||
|
||||
# Если токена нет, перенаправляем на страницу входа
|
||||
if not token:
|
||||
if path.startswith("/api/"):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Требуется аутентификация"
|
||||
)
|
||||
return RedirectResponse(url="/login", status_code=302)
|
||||
|
||||
# Проверяем токен
|
||||
try:
|
||||
payload = decode_access_token(token)
|
||||
if payload is None:
|
||||
# Токен невалидный или истек
|
||||
if path.startswith("/api/"):
|
||||
# Для API запросов возвращаем JSON с ошибкой
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Токен аутентификации истек или недействителен"
|
||||
)
|
||||
# Для HTML запросов перенаправляем на страницу входа
|
||||
return RedirectResponse(url="/login?expired=1", status_code=302)
|
||||
except Exception as e:
|
||||
# Ошибка при декодировании токена
|
||||
logger.warning(f"Error decoding token: {e}")
|
||||
if path.startswith("/api/"):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Ошибка проверки токена аутентификации"
|
||||
)
|
||||
return RedirectResponse(url="/login?expired=1", status_code=302)
|
||||
|
||||
# Добавляем пользователя в request state
|
||||
request.state.user = payload.get("sub")
|
||||
|
||||
return await call_next(request)
|
||||
Reference in New Issue
Block a user