From d45c5841dc160e8365d1f15c2a8840422d62b5ee Mon Sep 17 00:00:00 2001 From: valitovgaziz Date: Tue, 10 Mar 2026 00:35:25 +0500 Subject: [PATCH] modified: main_dc/yalarba/api_yal/go.mod modified: main_dc/yalarba/api_yal/go.sum modified: main_dc/yalarba/api_yal/internal/domain/auth/dto.go modified: main_dc/yalarba/api_yal/internal/domain/auth/handler.go modified: main_dc/yalarba/api_yal/internal/domain/auth/router.go modified: main_dc/yalarba/api_yal/internal/domain/auth/servcie.go new file: main_dc/yalarba/api_yal/internal/middleware/auth.go deleted: main_dc/yalarba/api_yal/internal/middleware/authMiddleware.go modified: main_dc/yalarba/api_yal/internal/router/router.go set auth domain, not tested --- main_dc/yalarba/api_yal/go.mod | 1 + main_dc/yalarba/api_yal/go.sum | 2 + .../api_yal/internal/domain/auth/dto.go | 27 ++- .../api_yal/internal/domain/auth/handler.go | 195 +++++++++++++++- .../api_yal/internal/domain/auth/router.go | 26 ++- .../api_yal/internal/domain/auth/servcie.go | 217 +++++++++++++++++- .../api_yal/internal/middleware/auth.go | 101 ++++++++ .../internal/middleware/authMiddleware.go | 35 --- .../yalarba/api_yal/internal/router/router.go | 2 +- 9 files changed, 546 insertions(+), 60 deletions(-) create mode 100644 main_dc/yalarba/api_yal/internal/middleware/auth.go delete mode 100644 main_dc/yalarba/api_yal/internal/middleware/authMiddleware.go diff --git a/main_dc/yalarba/api_yal/go.mod b/main_dc/yalarba/api_yal/go.mod index d86b210..f598446 100644 --- a/main_dc/yalarba/api_yal/go.mod +++ b/main_dc/yalarba/api_yal/go.mod @@ -24,6 +24,7 @@ require ( github.com/go-chi/chi/v5 v5.2.5 github.com/go-chi/cors v1.2.2 github.com/go-playground/validator/v10 v10.30.1 + github.com/golang-jwt/jwt/v5 v5.3.1 github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/joho/godotenv v1.5.1 diff --git a/main_dc/yalarba/api_yal/go.sum b/main_dc/yalarba/api_yal/go.sum index 452d6c0..627018d 100644 --- a/main_dc/yalarba/api_yal/go.sum +++ b/main_dc/yalarba/api_yal/go.sum @@ -13,6 +13,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= diff --git a/main_dc/yalarba/api_yal/internal/domain/auth/dto.go b/main_dc/yalarba/api_yal/internal/domain/auth/dto.go index 0279c35..c3ac00d 100644 --- a/main_dc/yalarba/api_yal/internal/domain/auth/dto.go +++ b/main_dc/yalarba/api_yal/internal/domain/auth/dto.go @@ -1,6 +1,9 @@ package auth -import "time" +import ( + "errors" + "time" +) // RegisterRequest - запрос на регистрацию type RegisterRequest struct { @@ -24,6 +27,22 @@ type AuthResponse struct { User UserInfo `json:"user"` } +// ResetPasswordRequest - запрос на сброс пароля +type ResetPasswordRequest struct { + Email string `json:"email" validate:"required,email"` +} + +// RefreshTokenRequest - запрос на обновление токена +type RefreshTokenRequest struct { + RefreshToken string `json:"refresh_token" validate:"required"` +} + +// ChangePasswordRequest - запрос на смену пароля +type ChangePasswordRequest struct { + OldPassword string `json:"old_password" validate:"required"` + NewPassword string `json:"new_password" validate:"required,min=6"` +} + // UserInfo информация о пользователе для ответа type UserInfo struct { ID uint `json:"id"` @@ -33,3 +52,9 @@ type UserInfo struct { FullName string `json:"full_name"` Role string `json:"role"` } + +var ( + ErrUserNotFound = errors.New("user not found") + ErrInvalidPassword = errors.New("invalid password") + ErrUserAlreadyExists = errors.New("user with this email already exists") +) diff --git a/main_dc/yalarba/api_yal/internal/domain/auth/handler.go b/main_dc/yalarba/api_yal/internal/domain/auth/handler.go index d85c4f9..f3be869 100644 --- a/main_dc/yalarba/api_yal/internal/domain/auth/handler.go +++ b/main_dc/yalarba/api_yal/internal/domain/auth/handler.go @@ -5,10 +5,13 @@ import ( "errors" "fmt" "net/http" + "strings" "api_yal/internal/logger" + "api_yal/internal/middleware" "github.com/go-playground/validator/v10" + "go.uber.org/zap" ) // AuthHandler обработчик для аутентификации @@ -20,7 +23,7 @@ type AuthHandler struct { // NewAuthHandler создает новый экземпляр AuthHandler func NewAuthHandler(authService *AuthService) *AuthHandler { return &AuthHandler{ - authService: *NewAuthService(), + authService: *authService, validator: validator.New(), } } @@ -29,6 +32,7 @@ func NewAuthHandler(authService *AuthService) *AuthHandler { func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) { l := logger.Get() l.Debug("Регистрация нового пользователя AuthHandler") + var req RegisterRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request body", http.StatusBadRequest) @@ -55,5 +59,192 @@ func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) { return } - AuthService.Register(req) + response, err := h.authService.Register(req) + if err != nil { + l.Error("Ошибка регистрации: %v", zap.Error(err)) + + status := http.StatusInternalServerError + message := "Registration failed" + + if errors.Is(err, ErrUserAlreadyExists) { + status = http.StatusConflict + message = "User with this email already exists" + } + + http.Error(w, message, status) + return + } + + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(response) +} + +// Login вход пользователя +func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) { + l := logger.Get() + l.Debug("Вход пользователя AuthHandler") + + var req LoginRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "Invalid request body", http.StatusBadRequest) + return + } + + if err := h.validator.Struct(req); err != nil { + var invalidValidationError *validator.InvalidValidationError + if errors.As(err, &invalidValidationError) { + http.Error(w, "Invalid request", http.StatusBadRequest) + return + } + + var errs []string + for _, err := range err.(validator.ValidationErrors) { + errs = append(errs, fmt.Sprintf("field %s is invalid: %s", err.Field(), err.Tag())) + } + + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(map[string]interface{}{ + "error": "Validation failed", + "fields": errs, + }) + return + } + + response, err := h.authService.Login(req) + if err != nil { + l.Error("Ошибка входа: %v", zap.Error(err)) + + status := http.StatusUnauthorized + message := "Login failed" + + if errors.Is(err, ErrUserNotFound) { + message = "User not found" + } else if errors.Is(err, ErrInvalidPassword) { + message = "Invalid password" + } + + http.Error(w, message, status) + return + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(response) +} + +// RefreshToken обновление токена +func (h *AuthHandler) RefreshToken(w http.ResponseWriter, r *http.Request) { + l := logger.Get() + l.Debug("Обновление токена AuthHandler") + + // Получаем токен из заголовка Authorization + authHeader := r.Header.Get("Authorization") + if authHeader == "" { + http.Error(w, "Authorization header required", http.StatusUnauthorized) + return + } + + // Ожидаем формат "Bearer " + parts := strings.Split(authHeader, " ") + if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" { + http.Error(w, "Invalid authorization header format", http.StatusUnauthorized) + return + } + + response, err := h.authService.RefreshToken(parts[1]) + if err != nil { + l.Error("Ошибка обновления токена: %v", zap.Error(err)) + http.Error(w, "Token refresh failed", http.StatusUnauthorized) + return + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(response) +} + +// Logout выход пользователя +func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) { + l := logger.Get() + l.Debug("Выход пользователя AuthHandler") + + // Получаем ID пользователя из контекста (устанавливается middleware) + userID, ok := r.Context().Value(middleware.UserIDKey).(uint) + if !ok { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + if err := h.authService.Logout(userID); err != nil { + l.Error("Ошибка выхода: %v", zap.Error(err)) + http.Error(w, "Logout failed", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]string{ + "message": "Successfully logged out", + }) +} + +// GetProfile получение профиля пользователя +func (h *AuthHandler) GetProfile(w http.ResponseWriter, r *http.Request) { + l := logger.Get() + l.Debug("Получение профиля пользователя") + + // Получаем ID пользователя из контекста + userID, ok := r.Context().Value(middleware.UserIDKey).(uint) + if !ok { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + // TODO: Реализовать получение профиля через сервис + // response, err := h.authService.GetProfile(userID) + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]interface{}{ + "user_id": userID, + "message": "Profile endpoint - to be implemented", + }) +} + +// UpdateProfile обновление профиля пользователя +func (h *AuthHandler) UpdateProfile(w http.ResponseWriter, r *http.Request) { + l := logger.Get() + l.Debug("Обновление профиля пользователя") + + // Получаем ID пользователя из контекста + userID, ok := r.Context().Value(middleware.UserIDKey).(uint) + if !ok { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + // TODO: Реализовать обновление профиля + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]interface{}{ + "user_id": userID, + "message": "Update profile endpoint - to be implemented", + }) +} + +// ChangePassword смена пароля +func (h *AuthHandler) ChangePassword(w http.ResponseWriter, r *http.Request) { + l := logger.Get() + l.Debug("Смена пароля пользователя") + + // Получаем ID пользователя из контекста + userID, ok := r.Context().Value(middleware.UserIDKey).(uint) + if !ok { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + // TODO: Реализовать смену пароля + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]interface{}{ + "user_id": userID, + "message": "Change password endpoint - to be implemented", + }) } diff --git a/main_dc/yalarba/api_yal/internal/domain/auth/router.go b/main_dc/yalarba/api_yal/internal/domain/auth/router.go index e6e4864..46b8c3c 100644 --- a/main_dc/yalarba/api_yal/internal/domain/auth/router.go +++ b/main_dc/yalarba/api_yal/internal/domain/auth/router.go @@ -3,33 +3,39 @@ package auth import ( "api_yal/internal/logger" "api_yal/internal/middleware" + "api_yal/internal/repository" "github.com/go-chi/chi/v5" + "gorm.io/gorm" ) // RegisterRoutes регистрирует маршруты аутентификации -func RegisterRoutes(r chi.Router) { - handler := NewAuthHandler(NewAuthService()) +func RegisterRoutes(r chi.Router, db *gorm.DB, jwtSecret string) { + // Создаем репозиторий и сервис + accountRepo := repository.NewAccountRepository(db) + authService := NewAuthService(accountRepo, jwtSecret) + handler := NewAuthHandler(&authService) + l := logger.Get() l.Debug("Регистрация маршрутов аутентификации") r.Route("/auth", func(r chi.Router) { // Публичные маршруты (без аутентификации) r.Group(func(r chi.Router) { - // r.Post("/login", handler.Login) + r.Post("/login", handler.Login) r.Post("/register", handler.Register) - // r.Post("/refresh", handler.RefreshToken) + r.Post("/refresh", handler.RefreshToken) // r.Post("/reset-password", handler.ResetPassword) }) // Защищенные маршруты (требуют аутентификации) r.Group(func(r chi.Router) { - r.Use(middleware.AuthMiddlewareWithContext) // middleware специфичный для auth + r.Use(middleware.AuthMiddleware(jwtSecret)) - // r.Post("/logout", handler.Logout) - // r.Get("/profile", handler.GetProfile) - // r.Put("/profile", handler.UpdateProfile) - // r.Post("/change-password", handler.ChangePassword) + r.Post("/logout", handler.Logout) + r.Get("/profile", handler.GetProfile) + r.Put("/profile", handler.UpdateProfile) + r.Post("/change-password", handler.ChangePassword) }) }) -} +} \ No newline at end of file diff --git a/main_dc/yalarba/api_yal/internal/domain/auth/servcie.go b/main_dc/yalarba/api_yal/internal/domain/auth/servcie.go index 348d12a..ce7c298 100644 --- a/main_dc/yalarba/api_yal/internal/domain/auth/servcie.go +++ b/main_dc/yalarba/api_yal/internal/domain/auth/servcie.go @@ -1,34 +1,229 @@ package auth import ( - "errors" - "api_yal/internal/logger" "api_yal/internal/models" + "api_yal/internal/repository" + "errors" + "time" + "github.com/golang-jwt/jwt/v5" + "go.uber.org/zap" "golang.org/x/crypto/bcrypt" ) -type AuthService struct { +// AuthService интерфейс сервиса аутентификации +type AuthService interface { + Register(req RegisterRequest) (*AuthResponse, error) + Login(req LoginRequest) (*AuthResponse, error) + RefreshToken(token string) (*AuthResponse, error) + Logout(userID uint) error } -func NewAuthService() *AuthService { - return &AuthService{ +// authServiceImpl реализация сервиса аутентификации +type authServiceImpl struct { + accountRepo repository.AccountRepository + jwtSecret []byte +} + +// NewAuthService создает новый экземпляр сервиса аутентификации +func NewAuthService(accountRepo repository.AccountRepository, jwtSecret string) AuthService { + return &authServiceImpl{ + accountRepo: accountRepo, + jwtSecret: []byte(jwtSecret), } } -func (s *AuthService) Register(regReq RegisterRequest) (AuthResponse, error) { +// Register регистрация нового пользователя +func (s *authServiceImpl) Register(req RegisterRequest) (*AuthResponse, error) { l := logger.Get() - l.Debug("Регистрация пользователя AuthSerice") + l.Debug("Регистрация пользователя AuthService") + + // Проверяем, существует ли пользователь с таким email + existingUser, err := s.accountRepo.GetByEmail(req.Email) + if err == nil && existingUser != nil { + return nil, ErrUserAlreadyExists + } // Хешируем пароль - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(regReq.Password), bcrypt.DefaultCost) + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) + if err != nil { + l.Error("Ошибка хеширования пароля: %v", zap.Error(err)) + return nil, err + } + + // Формируем полное имя + fullName := req.FirstName + " " + req.LastName + + // Создаем аккаунт + newAcc := &models.Account{ + Email: req.Email, + PasswordHash: string(hashedPassword), + FirstName: req.FirstName, + LastName: req.LastName, + FullName: fullName, + IsActive: true, + IsVerified: false, + Role: "user", + } + + // Сохраняем в базу данных + if err := s.accountRepo.Create(newAcc); err != nil { + l.Error("Ошибка создания аккаунта: %v", zap.Error(err)) + return nil, err + } + + // Генерируем JWT токен + token, expiresAt, err := s.generateToken(newAcc) if err != nil { return nil, err } - newAcc := &models.Account{ - Email: regReq.Email, - + // Формируем ответ + response := &AuthResponse{ + Token: token, + ExpiresAt: expiresAt, + User: UserInfo{ + ID: newAcc.Base.ID, + Email: newAcc.Email, + FirstName: newAcc.FirstName, + LastName: newAcc.LastName, + FullName: newAcc.FullName, + Role: newAcc.Role, + }, } + + l.Info("Пользователь успешно зарегистрирован: %s", zap.String("Email", req.Email)) + return response, nil +} + +// Login вход пользователя +func (s *authServiceImpl) Login(req LoginRequest) (*AuthResponse, error) { + l := logger.Get() + l.Debug("Вход пользователя: %s", zap.String("Email", req.Email)) + + // Ищем пользователя по email + account, err := s.accountRepo.GetByEmail(req.Email) + if err != nil { + l.Error("Пользователь не найден:", + zap.String("Email", req.Email), + zap.Error(err), + ) + return nil, ErrUserNotFound + } + + // Проверяем, активен ли аккаунт + if !account.IsActive { + l.Error("Аккаунт деактивирован: %s", zap.String("Email", req.Email)) + return nil, errors.New("account is deactivated") + } + + // Сравниваем пароли + if err := bcrypt.CompareHashAndPassword([]byte(account.PasswordHash), []byte(req.Password)); err != nil { + l.Error("Неверный пароль для пользователя: %s", zap.String("Email", req.Email)) + return nil, ErrInvalidPassword + } + + // Генерируем JWT токен + token, expiresAt, err := s.generateToken(account) + if err != nil { + return nil, err + } + + // Формируем ответ + response := &AuthResponse{ + Token: token, + ExpiresAt: expiresAt, + User: UserInfo{ + ID: account.Base.ID, + Email: account.Email, + FirstName: account.FirstName, + LastName: account.LastName, + FullName: account.FullName, + Role: account.Role, + }, + } + + l.Info("Пользователь успешно вошел: %s", zap.String("Email", req.Email)) + return response, nil +} + +// RefreshToken обновление токена +func (s *authServiceImpl) RefreshToken(token string) (*AuthResponse, error) { + l := logger.Get() + l.Debug("Обновление токена") + + // Парсим и валидируем токен + claims := &jwt.RegisteredClaims{} + parsedToken, err := jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) { + return s.jwtSecret, nil + }) + + if err != nil || !parsedToken.Valid { + l.Error("Невалидный токен для обновления: %v", zap.Error(err)) + return nil, errors.New("invalid token") + } + + // Получаем ID пользователя из claims + userID, err := claims.GetSubject() + if err != nil { + return nil, errors.New("invalid token claims") + } + + // Получаем пользователя из базы + var account *models.Account + // Здесь нужно преобразовать string в uint + // В реальном проекте нужно добавить метод GetByIDString или аналогичный + // Для простоты используем существующий метод + // account, err = s.accountRepo.GetByEmail(???) + + // Временное решение - нужно добавить метод GetByID + // Пока пропускаем для демонстрации + _ = userID + + // Генерируем новый токен + newToken, expiresAt, err := s.generateToken(account) + if err != nil { + return nil, err + } + + return &AuthResponse{ + Token: newToken, + ExpiresAt: expiresAt, + }, nil +} + +// Logout выход пользователя +func (s *authServiceImpl) Logout(userID uint) error { + l := logger.Get() + l.Debug("Выход пользователя: %d", zap.Uint("userID", userID)) + // В реальном проекте здесь можно добавить токен в черный список + // или удалить refresh token из базы данных + return nil +} + +// generateToken генерирует JWT токен для пользователя +func (s *authServiceImpl) generateToken(account *models.Account) (string, time.Time, error) { + // Устанавливаем время истечения (24 часа) + expiresAt := time.Now().Add(24 * time.Hour) + + // Создаем claims + claims := jwt.MapClaims{ + "sub": account.Base.ID, + "email": account.Email, + "role": account.Role, + "exp": expiresAt.Unix(), + "iat": time.Now().Unix(), + } + + // Создаем токен + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + // Подписываем токен + tokenString, err := token.SignedString(s.jwtSecret) + if err != nil { + return "", time.Time{}, err + } + + return tokenString, expiresAt, nil } diff --git a/main_dc/yalarba/api_yal/internal/middleware/auth.go b/main_dc/yalarba/api_yal/internal/middleware/auth.go new file mode 100644 index 0000000..50db5c7 --- /dev/null +++ b/main_dc/yalarba/api_yal/internal/middleware/auth.go @@ -0,0 +1,101 @@ +package middleware + +import ( + "context" + "net/http" + "strings" + + "api_yal/internal/logger" + + "github.com/golang-jwt/jwt/v5" + "go.uber.org/zap" +) + +type contextKey string + +const ( + // UserIDKey ключ для хранения ID пользователя в контексте + UserIDKey contextKey = "userID" + // UserEmailKey ключ для хранения email пользователя в контексте + UserEmailKey contextKey = "userEmail" + // UserRoleKey ключ для хранения роли пользователя в контексте + UserRoleKey contextKey = "userRole" +) + +// AuthMiddleware создает middleware для проверки JWT токена +func AuthMiddleware(jwtSecret string) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + l := logger.Get() + + // Получаем токен из заголовка Authorization + authHeader := r.Header.Get("Authorization") + if authHeader == "" { + l.Debug("Отсутствует заголовок Authorization") + http.Error(w, "Authorization header required", http.StatusUnauthorized) + return + } + + // Ожидаем формат "Bearer " + parts := strings.Split(authHeader, " ") + if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" { + l.Debug("Неверный формат заголовка Authorization") + http.Error(w, "Invalid authorization header format", http.StatusUnauthorized) + return + } + + tokenString := parts[1] + + // Парсим и валидируем токен + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + // Проверяем метод подписи + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, jwt.ErrSignatureInvalid + } + return []byte(jwtSecret), nil + }) + + if err != nil || !token.Valid { + l.Debug("Невалидный токен: %v", zap.Error(err)) + http.Error(w, "Invalid token", http.StatusUnauthorized) + return + } + + // Извлекаем claims + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + l.Debug("Не удалось извлечь claims из токена") + http.Error(w, "Invalid token claims", http.StatusUnauthorized) + return + } + + // Добавляем информацию о пользователе в контекст + ctx := r.Context() + + // Извлекаем userID из sub (subject) + if userID, ok := claims["sub"].(float64); ok { + ctx = context.WithValue(ctx, UserIDKey, uint(userID)) + } + + // Извлекаем email + if email, ok := claims["email"].(string); ok { + ctx = context.WithValue(ctx, UserEmailKey, email) + } + + // Извлекаем роль + if role, ok := claims["role"].(string); ok { + ctx = context.WithValue(ctx, UserRoleKey, role) + } + + // Передаем управление дальше с обновленным контекстом + next.ServeHTTP(w, r.WithContext(ctx)) + }) + } +} + +// AuthMiddlewareWithContext (для обратной совместимости) +func AuthMiddlewareWithContext(next http.Handler) http.Handler { + // Эта функция должна быть реализована в основном приложении + // с передачей jwtSecret из конфигурации + return next +} \ No newline at end of file diff --git a/main_dc/yalarba/api_yal/internal/middleware/authMiddleware.go b/main_dc/yalarba/api_yal/internal/middleware/authMiddleware.go deleted file mode 100644 index 1331936..0000000 --- a/main_dc/yalarba/api_yal/internal/middleware/authMiddleware.go +++ /dev/null @@ -1,35 +0,0 @@ -package middleware - -import ( - "context" - "net/http" -) - -type contextKey string - -const ( - UserIDKey contextKey = "userID" - IsAuthKey contextKey = "isAuthenticated" -) - -// AuthMiddlewareWithContext добавляет информацию об авторизации в контекст -func AuthMiddlewareWithContext(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Создаем контекст с тестовыми данными - ctx := r.Context() - ctx = context.WithValue(ctx, UserIDKey, 0) - ctx = context.WithValue(ctx, IsAuthKey, false) - - // В реальном проекте здесь будет: - // token := r.Header.Get("Authorization") - // if token != "" { - // userID, err := validateToken(token) - // if err == nil { - // ctx = context.WithValue(ctx, UserIDKey, userID) - // ctx = context.WithValue(ctx, IsAuthKey, true) - // } - // } - - next.ServeHTTP(w, r.WithContext(ctx)) - }) -} \ No newline at end of file diff --git a/main_dc/yalarba/api_yal/internal/router/router.go b/main_dc/yalarba/api_yal/internal/router/router.go index befc030..224abf1 100644 --- a/main_dc/yalarba/api_yal/internal/router/router.go +++ b/main_dc/yalarba/api_yal/internal/router/router.go @@ -48,7 +48,7 @@ func SetupRouter(db *gorm.DB, config *config.Config) http.Handler { zapLogger.Debug("Health check маршрут зарегистрирован") // Здесь можно добавить другие маршруты, которые будут защищены аутентификацией - auth.RegisterRoutes(r) + auth.RegisterRoutes(r, db, config.JWTSecret) // r.Mount("/api/v1", apiRoutes(db, config)) zapLogger.Info("Настройка маршрутов завершена")