142 lines
3.3 KiB
Go
142 lines
3.3 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
|
|
"counter/internal/domain/entities"
|
|
"counter/internal/domain/repositories"
|
|
"counter/internal/infrastructure/security"
|
|
)
|
|
|
|
// AuthService handles authentication business logic
|
|
type AuthService struct {
|
|
userRepo repositories.UserRepository
|
|
passwordService security.PasswordService
|
|
jwtService security.JWTService
|
|
}
|
|
|
|
// NewAuthService creates a new authentication service
|
|
func NewAuthService(
|
|
userRepo repositories.UserRepository,
|
|
passwordService security.PasswordService,
|
|
jwtService security.JWTService,
|
|
) *AuthService {
|
|
return &AuthService{
|
|
userRepo: userRepo,
|
|
passwordService: passwordService,
|
|
jwtService: jwtService,
|
|
}
|
|
}
|
|
|
|
// RegisterRequest represents a user registration request
|
|
type RegisterRequest struct {
|
|
Username string `json:"username" binding:"required,min=3,max=50"`
|
|
Email string `json:"email" binding:"required,email"`
|
|
Password string `json:"password" binding:"required,min=6"`
|
|
}
|
|
|
|
// LoginRequest represents a user login request
|
|
type LoginRequest struct {
|
|
Username string `json:"username" binding:"required"`
|
|
Password string `json:"password" binding:"required"`
|
|
}
|
|
|
|
// AuthResponse represents an authentication response
|
|
type AuthResponse struct {
|
|
Token string `json:"token"`
|
|
User *entities.User `json:"user"`
|
|
}
|
|
|
|
// Register registers a new user
|
|
func (s *AuthService) Register(ctx context.Context, req *RegisterRequest) (*AuthResponse, error) {
|
|
// Check if username already exists
|
|
_, err := s.userRepo.FindByUsername(ctx, req.Username)
|
|
if err == nil {
|
|
return nil, entities.ErrUserAlreadyExists
|
|
}
|
|
if err != entities.ErrUserNotFound {
|
|
return nil, err
|
|
}
|
|
|
|
// Check if email already exists
|
|
_, err = s.userRepo.FindByEmail(ctx, req.Email)
|
|
if err == nil {
|
|
return nil, entities.ErrUserAlreadyExists
|
|
}
|
|
if err != entities.ErrUserNotFound {
|
|
return nil, err
|
|
}
|
|
|
|
// Hash password
|
|
hashedPassword, err := s.passwordService.HashPassword(req.Password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create user
|
|
user := &entities.User{
|
|
Username: req.Username,
|
|
Email: req.Email,
|
|
Password: hashedPassword,
|
|
}
|
|
|
|
if err := s.userRepo.Create(ctx, user); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Generate token
|
|
token, err := s.jwtService.GenerateToken(user.ID, user.Username)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Clear password from response
|
|
user.ClearPassword()
|
|
|
|
return &AuthResponse{
|
|
Token: token,
|
|
User: user,
|
|
}, nil
|
|
}
|
|
|
|
// Login authenticates a user
|
|
func (s *AuthService) Login(ctx context.Context, req *LoginRequest) (*AuthResponse, error) {
|
|
// Find user
|
|
user, err := s.userRepo.FindByUsername(ctx, req.Username)
|
|
if err != nil {
|
|
return nil, entities.ErrInvalidCredentials
|
|
}
|
|
|
|
// Check password
|
|
if !s.passwordService.CheckPasswordHash(req.Password, user.Password) {
|
|
return nil, entities.ErrInvalidCredentials
|
|
}
|
|
|
|
// Generate token
|
|
token, err := s.jwtService.GenerateToken(user.ID, user.Username)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Clear password from response
|
|
user.ClearPassword()
|
|
|
|
return &AuthResponse{
|
|
Token: token,
|
|
User: user,
|
|
}, nil
|
|
}
|
|
|
|
// GetCurrentUser retrieves the current authenticated user
|
|
func (s *AuthService) GetCurrentUser(ctx context.Context, userID int) (*entities.User, error) {
|
|
user, err := s.userRepo.FindByID(ctx, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Clear password from response
|
|
user.ClearPassword()
|
|
|
|
return user, nil
|
|
}
|