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:
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user