On branch main

modified:   internal/domain/auth/dto.go
	modified:   internal/domain/auth/handler.go
	modified:   internal/domain/auth/router.go
	modified:   internal/domain/auth/servcie.go
	modified:   internal/middleware/auth.go
	modified:   internal/router/router.go
auth implemented without reset password
This commit is contained in:
2026-03-31 04:22:54 +05:00
parent 659cd3584c
commit 8b40d1bfe5
6 changed files with 372 additions and 119 deletions
@@ -1,7 +1,9 @@
// middleware/auth.go (обновленная версия с логированием)
package middleware
import (
"context"
"fmt"
"net/http"
"strings"
@@ -14,12 +16,9 @@ import (
type contextKey string
const (
// UserIDKey ключ для хранения ID пользователя в контексте
UserIDKey contextKey = "userID"
// UserEmailKey ключ для хранения email пользователя в контексте
UserIDKey contextKey = "userID"
UserEmailKey contextKey = "userEmail"
// UserRoleKey ключ для хранения роли пользователя в контексте
UserRoleKey contextKey = "userRole"
UserRoleKey contextKey = "userRole"
)
// AuthMiddleware создает middleware для проверки JWT токена
@@ -28,10 +27,15 @@ func AuthMiddleware(jwtSecret string) func(http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
l.Info("=== AUTH MIDDLEWARE START ===")
l.Info("Request path", zap.String("path", r.URL.Path))
// Получаем токен из заголовка Authorization
authHeader := r.Header.Get("Authorization")
l.Info("Authorization header", zap.String("header", authHeader))
if authHeader == "" {
l.Debug("Отсутствует заголовок Authorization")
l.Warn("Отсутствует заголовок Authorization")
http.Error(w, "Authorization header required", http.StatusUnauthorized)
return
}
@@ -39,63 +43,101 @@ func AuthMiddleware(jwtSecret string) func(http.Handler) http.Handler {
// Ожидаем формат "Bearer <token>"
parts := strings.Split(authHeader, " ")
if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
l.Debug("Неверный формат заголовка Authorization")
l.Warn("Неверный формат заголовка Authorization",
zap.Int("parts_count", len(parts)),
zap.String("first_part", parts[0]))
http.Error(w, "Invalid authorization header format", http.StatusUnauthorized)
return
}
tokenString := parts[1]
l.Info("Token extracted", zap.String("token_preview", tokenString[:min(20, len(tokenString))]+"..."))
// Парсим и валидируем токен
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// Проверяем метод подписи
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
l.Error("Unexpected signing method",
zap.String("method", token.Method.Alg()))
return nil, jwt.ErrSignatureInvalid
}
return []byte(jwtSecret), nil
})
if err != nil || !token.Valid {
l.Debug("Невалидный токен: %v", zap.Error(err))
if err != nil {
l.Error("Token parse error", zap.Error(err))
http.Error(w, "Invalid token: "+err.Error(), http.StatusUnauthorized)
return
}
if !token.Valid {
l.Error("Token is not valid")
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
l.Info("Token is valid")
// Извлекаем claims
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
l.Debug("Не удалось извлечь claims из токена")
l.Error("Failed to extract claims")
http.Error(w, "Invalid token claims", http.StatusUnauthorized)
return
}
l.Info("Claims extracted", zap.Any("claims", claims))
// Проверяем тип токена (должен быть access)
if tokenType, exists := claims["type"]; exists {
l.Info("Token type", zap.String("type", tokenType.(string)))
if tokenType != "access" {
l.Error("Wrong token type, expected access", zap.String("type", tokenType.(string)))
http.Error(w, "Invalid token type", http.StatusUnauthorized)
return
}
}
// Добавляем информацию о пользователе в контекст
ctx := r.Context()
// Извлекаем userID из sub (subject)
if userID, ok := claims["sub"].(float64); ok {
ctx = context.WithValue(ctx, UserIDKey, uint(userID))
// В claims sub хранится как string, а не float64
if userID, ok := claims["sub"].(string); ok {
l.Info("User ID from claims", zap.String("user_id_str", userID))
// Конвертируем string в uint
var userIDUint uint
if _, err := fmt.Sscan(userID, &userIDUint); err == nil {
ctx = context.WithValue(ctx, UserIDKey, userIDUint)
l.Info("User ID added to context", zap.Uint("user_id", userIDUint))
}
} else {
l.Error("sub claim not found or wrong type")
}
// Извлекаем email
if email, ok := claims["email"].(string); ok {
ctx = context.WithValue(ctx, UserEmailKey, email)
l.Info("Email added to context", zap.String("email", email))
}
// Извлекаем роль
if role, ok := claims["role"].(string); ok {
ctx = context.WithValue(ctx, UserRoleKey, role)
l.Info("Role added to context", zap.String("role", role))
}
l.Info("=== AUTH MIDDLEWARE END ===")
// Передаем управление дальше с обновленным контекстом
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
// AuthMiddlewareWithContext (для обратной совместимости)
func AuthMiddlewareWithContext(next http.Handler) http.Handler {
// Эта функция должна быть реализована в основном приложении
// с передачей jwtSecret из конфигурации
return next
func min(a, b int) int {
if a < b {
return a
}
return b
}