// middleware/auth.go package middleware import ( "context" "net/http" "strings" "api_bb/internal/models" "api_bb/internal/repository" "api_bb/internal/service" "api_bb/pkg/logger" "go.uber.org/zap" ) type contextKey string const ( UserIDKey contextKey = "userID" UserKey contextKey = "user" ) func AuthMiddleware(jwtService service.JWTService, userRepo repository.UserRepository) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var tokenString string logger := logger.Get() logger.Debug("authMiddleware Start") // Пробуем получить токен из заголовка Authorization authHeader := r.Header.Get("Authorization") if strings.HasPrefix(authHeader, "Bearer ") { tokenString = strings.TrimPrefix(authHeader, "Bearer ") logger.Debug("Token found in Authorization header") } // Если нет в заголовке, пробуем из куки if tokenString == "" { cookie, err := r.Cookie("auth_token") if err == nil { tokenString = cookie.Value logger.Debug("Token found in auth_token cookie") } else { logger.Debug("No auth_token cookie found", zap.Error(err)) } } if tokenString == "" { logger.Debug("No token found in request") next.ServeHTTP(w, r) return } token, err := jwtService.ValidateToken(tokenString) if err != nil || !token.Valid { logger.Warn("Invalid token", zap.Error(err), zap.Bool("token_valid", token != nil && token.Valid)) next.ServeHTTP(w, r) return } userID, err := jwtService.ExtractUserID(token) if err != nil { logger.Error("Failed to extract user ID from token", zap.Error(err)) next.ServeHTTP(w, r) return } logger.Debug("Extracted user ID from token", zap.Any("user_id", userID)) user, err := userRepo.FindByID(userID) if err != nil { logger.Error("Failed to find user by ID", zap.Any("user_id", userID), zap.Error(err)) next.ServeHTTP(w, r) return } // Добавляем пользователя в контекст ctx := context.WithValue(r.Context(), UserIDKey, userID) ctx = context.WithValue(ctx, UserKey, user) logger.Debug("User authenticated successfully", zap.Any("user_id", userID), zap.String("username", user.FirstName)) logger.Debug("authMiddleware End") next.ServeHTTP(w, r.WithContext(ctx)) }) } } // RequireAuth middleware требует аутентификации func RequireAuth(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { logger := logger.Get() userID := r.Context().Value(UserIDKey) logger.Debug("RequireAuth method start") logger.Debug("Extracted user ID from token", zap.Any("user_id", userID)) if userID == nil { logger.Warn("Authentication required but no user ID in context") http.Error(w, `{"error": "Authentication required"}`, http.StatusUnauthorized) return } logger.Debug("User authenticated", zap.Any("user_id", userID)) logger.Debug("authMiddleware End") next.ServeHTTP(w, r) }) } // GetUserFromContext получает пользователя из контекста func GetUserFromContext(ctx context.Context) (*models.User, bool) { logger := logger.Get() user, ok := ctx.Value(UserKey).(*models.User) logger.Debug("GetUserFromContext method") logger.Debug("Extracted user ID from token", zap.Any("user_id", user.ID)) if !ok { logger.Debug("No user found in context") } else { logger.Debug("User retrieved from context", zap.Any("user_id", user.ID), zap.String("username", user.FirstName)) } return user, ok }