Files
tp/main_dc/yalarba/api_yal/internal/domain/auth/servcie.go
T
valitovgaziz d45c5841dc 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
2026-03-10 00:35:25 +05:00

230 lines
7.0 KiB
Go

package auth
import (
"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"
)
// AuthService интерфейс сервиса аутентификации
type AuthService interface {
Register(req RegisterRequest) (*AuthResponse, error)
Login(req LoginRequest) (*AuthResponse, error)
RefreshToken(token string) (*AuthResponse, error)
Logout(userID uint) error
}
// 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),
}
}
// Register регистрация нового пользователя
func (s *authServiceImpl) Register(req RegisterRequest) (*AuthResponse, error) {
l := logger.Get()
l.Debug("Регистрация пользователя AuthService")
// Проверяем, существует ли пользователь с таким email
existingUser, err := s.accountRepo.GetByEmail(req.Email)
if err == nil && existingUser != nil {
return nil, ErrUserAlreadyExists
}
// Хешируем пароль
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
}
// Формируем ответ
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
}