modified: main_dc/yalarba/api_yal/internal/router/router.go
fix bag with auth before router paths
This commit is contained in:
@@ -17,33 +17,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// SetupRouter инициализирует и настраивает основной маршрутизатор приложения
|
// SetupRouter инициализирует и настраивает основной маршрутизатор приложения
|
||||||
// Параметры:
|
|
||||||
// - db: подключение к базе данных GORM
|
|
||||||
// - config: конфигурация приложения
|
|
||||||
//
|
|
||||||
// Возвращает:
|
|
||||||
// - http.Handler: настроенный маршрутизатор с применёнными middleware и маршрутами
|
|
||||||
func SetupRouter(db *gorm.DB, config *config.Config) http.Handler {
|
func SetupRouter(db *gorm.DB, config *config.Config) http.Handler {
|
||||||
// Получаем экземпляр логгера для записи событий
|
|
||||||
zapLogger := logger.Get()
|
zapLogger := logger.Get()
|
||||||
zapLogger.Info("Начало настройки маршрутов")
|
zapLogger.Info("Начало настройки маршрутов")
|
||||||
|
|
||||||
// Создаём новый экземпляр маршрутизатора chi
|
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
|
||||||
// Добавляем все production middleware для обработки входящих запросов
|
// ВСЕ middleware должны быть определены ДО маршрутов
|
||||||
|
// 1. Сначала добавляем production middleware
|
||||||
addProductionMiddleware(r, config)
|
addProductionMiddleware(r, config)
|
||||||
zapLogger.Debug("Production middleware успешно добавлены")
|
|
||||||
|
// 2. Затем добавляем middleware аутентификации (он тоже применяется ко всем маршрутам)
|
||||||
|
r.Use(CastomMiddleware.AuthMiddlewareWithContext)
|
||||||
|
zapLogger.Debug("Auth middleware применён")
|
||||||
|
|
||||||
// Эндпоинт для проверки работоспособности сервиса (health check)
|
// 3. И только потом регистрируем маршруты
|
||||||
// Используется мониторингом и системами оркестрации для проверки статуса приложения
|
// Health check (не требует аутентификации, поэтому должен быть выше AuthMiddleware)
|
||||||
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
// Формируем и отправляем JSON-ответ со статусом healthy
|
|
||||||
if err := json.NewEncoder(w).Encode(map[string]string{"status": "healthy"}); err != nil {
|
if err := json.NewEncoder(w).Encode(map[string]string{"status": "healthy"}); err != nil {
|
||||||
// Логируем ошибку при невозможности отправить ответ
|
|
||||||
zapLogger.Error("Ошибка при отправке health check ответа",
|
zapLogger.Error("Ошибка при отправке health check ответа",
|
||||||
zap.String("path", r.URL.Path),
|
zap.String("path", r.URL.Path),
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
@@ -52,123 +46,60 @@ func SetupRouter(db *gorm.DB, config *config.Config) http.Handler {
|
|||||||
})
|
})
|
||||||
zapLogger.Debug("Health check маршрут зарегистрирован")
|
zapLogger.Debug("Health check маршрут зарегистрирован")
|
||||||
|
|
||||||
// Добавляем middleware для аутентификации ко всем последующим маршрутам
|
// Здесь можно добавить другие маршруты, которые будут защищены аутентификацией
|
||||||
// Все маршруты после этого middleware будут требовать валидный контекст аутентификации
|
// r.Mount("/api/v1", apiRoutes(db, config))
|
||||||
r.Use(CastomMiddleware.AuthMiddlewareWithContext)
|
|
||||||
zapLogger.Debug("Auth middleware применён ко всем маршрутам")
|
|
||||||
|
|
||||||
// TODO: Здесь можно добавить регистрацию дополнительных маршрутов
|
zapLogger.Info("Настройка маршрутов завершена")
|
||||||
// Например: r.Mount("/api/v1", apiRoutes(db, config))
|
|
||||||
|
|
||||||
zapLogger.Info("Настройка маршрутов завершена успешно")
|
// Логируем маршруты (опционально)
|
||||||
|
|
||||||
// Логируем все зарегистрированные маршруты для отладки и мониторинга
|
|
||||||
routeLogger := logger.NewRouteLogger(logger.NewWrapper(zapLogger))
|
routeLogger := logger.NewRouteLogger(logger.NewWrapper(zapLogger))
|
||||||
routeLogger.LogRoutes(r)
|
routeLogger.LogRoutes(r)
|
||||||
zapLogger.Debug("Все маршруты залогированы")
|
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// addProductionMiddleware добавляет все необходимые middleware для production окружения
|
// addProductionMiddleware добавляет все middleware для production
|
||||||
// Функция применяет стандартный набор middleware для обработки запросов:
|
|
||||||
// - Идентификация запросов
|
|
||||||
// - Логирование
|
|
||||||
// - Безопасность
|
|
||||||
// - Сжатие ответов
|
|
||||||
// - CORS настройки
|
|
||||||
//
|
|
||||||
// Параметры:
|
|
||||||
// - r: экземпляр маршрутизатора chi
|
|
||||||
// - config: конфигурация приложения для настройки middleware под окружение
|
|
||||||
func addProductionMiddleware(r *chi.Mux, config *config.Config) {
|
func addProductionMiddleware(r *chi.Mux, config *config.Config) {
|
||||||
// Request ID middleware - добавляет уникальный ID к каждому запросу
|
// Базовые middleware
|
||||||
// Позволяет отслеживать запрос на протяжении всего жизненного цикла
|
|
||||||
r.Use(ChiMiddleware.RequestID)
|
r.Use(ChiMiddleware.RequestID)
|
||||||
|
|
||||||
// Real IP middleware - корректно определяет реальный IP клиента (за прокси)
|
|
||||||
// Важно для правильного логирования и rate limiting'а
|
|
||||||
r.Use(ChiMiddleware.RealIP)
|
r.Use(ChiMiddleware.RealIP)
|
||||||
|
|
||||||
// Logger middleware - логирует все запросы в формате Apache
|
|
||||||
// Предоставляет базовую информацию о входящих запросах
|
|
||||||
r.Use(ChiMiddleware.Logger)
|
r.Use(ChiMiddleware.Logger)
|
||||||
|
|
||||||
// Recoverer middleware - восстанавливает после паники и возвращает 500
|
|
||||||
// Предотвращает падение всего приложения из-за паники в обработчиках
|
|
||||||
r.Use(ChiMiddleware.Recoverer)
|
r.Use(ChiMiddleware.Recoverer)
|
||||||
|
|
||||||
// Timeout middleware - устанавливает таймаут на запросы (30 секунд)
|
|
||||||
// Защищает от "висящих" запросов, которые могут занять слишком много времени
|
|
||||||
r.Use(ChiMiddleware.Timeout(30 * time.Second))
|
r.Use(ChiMiddleware.Timeout(30 * time.Second))
|
||||||
|
|
||||||
// Compress middleware - сжимает ответы (gzip)
|
|
||||||
// Уменьшает размер передаваемых данных, улучшает производительность
|
|
||||||
// Уровень сжатия 5 (среднее между скоростью и степенью сжатия)
|
|
||||||
r.Use(ChiMiddleware.Compress(5, "gzip"))
|
r.Use(ChiMiddleware.Compress(5, "gzip"))
|
||||||
|
|
||||||
// StripSlashes middleware - удаляет слеши в конце URL или редиректит
|
|
||||||
// Нормализует URL'ы для единообразия маршрутизации
|
|
||||||
r.Use(ChiMiddleware.StripSlashes)
|
r.Use(ChiMiddleware.StripSlashes)
|
||||||
|
|
||||||
// CORS middleware - настройка CORS для production
|
// CORS
|
||||||
// Позволяет контролировать доступ к API из браузерных приложений
|
|
||||||
r.Use(cors.Handler(cors.Options{
|
r.Use(cors.Handler(cors.Options{
|
||||||
// Разрешённые источники (origins) из конфигурации
|
AllowedOrigins: config.CORS.AllowedOrigins,
|
||||||
AllowedOrigins: config.CORS.AllowedOrigins,
|
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"},
|
||||||
// Разрешённые HTTP методы
|
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token", "X-Request-ID"},
|
||||||
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"},
|
ExposedHeaders: []string{"Link", "X-Request-ID"},
|
||||||
// Разрешённые заголовки запросов
|
|
||||||
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token", "X-Request-ID"},
|
|
||||||
// Заголовки, доступные клиенту при чтении ответа
|
|
||||||
ExposedHeaders: []string{"Link", "X-Request-ID"},
|
|
||||||
// Разрешить передачу cookies и HTTP-аутентификацию
|
|
||||||
AllowCredentials: true,
|
AllowCredentials: true,
|
||||||
// Время кэширования preflight запросов (в секундах)
|
MaxAge: 300,
|
||||||
MaxAge: 300,
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Content-Type middleware - проверяет Content-Type для POST/PUT запросов
|
// Content-Type проверка
|
||||||
// Гарантирует, что клиенты отправляют данные в ожидаемом формате
|
|
||||||
r.Use(ChiMiddleware.AllowContentType("application/json", "application/xml"))
|
r.Use(ChiMiddleware.AllowContentType("application/json", "application/xml"))
|
||||||
|
|
||||||
// Дополнительные middleware в зависимости от конфигурации
|
// Rate limiting
|
||||||
if config.Environment == "development" {
|
|
||||||
// Добавляем дополнительное логирование для разработки
|
|
||||||
// В dev-режиме полезно иметь более подробную информацию о запросах
|
|
||||||
r.Use(ChiMiddleware.Logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.RateLimit.Enabled {
|
if config.RateLimit.Enabled {
|
||||||
// Добавляем rate limiting если включено в конфиге
|
|
||||||
// Защищает от DDoS атак и чрезмерного использования ресурсов
|
|
||||||
r.Use(ChiMiddleware.Throttle(config.RateLimit.RequestsPerSecond))
|
r.Use(ChiMiddleware.Throttle(config.RateLimit.RequestsPerSecond))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Security headers middleware - добавляет заголовки безопасности к каждому ответу
|
// Security headers
|
||||||
// Защищает от распространённых веб-уязвимостей
|
|
||||||
r.Use(func(next http.Handler) http.Handler {
|
r.Use(func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Защита от MIME-снiffing атак
|
|
||||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
|
||||||
// Защита от clickjacking атак
|
|
||||||
w.Header().Set("X-Frame-Options", "DENY")
|
w.Header().Set("X-Frame-Options", "DENY")
|
||||||
|
|
||||||
// Включает защиту от XSS в браузерах
|
|
||||||
w.Header().Set("X-XSS-Protection", "1; mode=block")
|
w.Header().Set("X-XSS-Protection", "1; mode=block")
|
||||||
|
|
||||||
// Контролирует, сколько информации о реферере передаётся при переходах
|
|
||||||
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
|
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
|
||||||
|
|
||||||
// Для production окружения включаем HSTS (HTTP Strict Transport Security)
|
|
||||||
// Заставляет браузер использовать только HTTPS соединения
|
|
||||||
if config.Environment == "production" {
|
if config.Environment == "production" {
|
||||||
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
|
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Передаём управление следующему middleware или обработчику
|
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user