package services import ( "api-service/internal/config" models "api-service/internal/models/auth" "errors" "time" "github.com/golang-jwt/jwt/v5" "golang.org/x/crypto/bcrypt" ) // AuthService handles authentication logic type AuthService struct { config *config.Config users map[string]*models.User // In-memory user store for demo } // NewAuthService creates a new authentication service func NewAuthService(cfg *config.Config) *AuthService { // Initialize with demo users users := make(map[string]*models.User) // Add demo users users["admin"] = &models.User{ ID: "1", Username: "admin", Email: "admin@example.com", Password: "$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", // password Role: "admin", } users["user"] = &models.User{ ID: "2", Username: "user", Email: "user@example.com", Password: "$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", // password Role: "user", } return &AuthService{ config: cfg, users: users, } } // Login authenticates user and generates JWT token func (s *AuthService) Login(username, password string) (*models.TokenResponse, error) { user, exists := s.users[username] if !exists { return nil, errors.New("invalid credentials") } // Verify password err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) if err != nil { return nil, errors.New("invalid credentials") } // Generate JWT token token, err := s.generateToken(user) if err != nil { return nil, err } return &models.TokenResponse{ AccessToken: token, TokenType: "Bearer", ExpiresIn: 3600, // 1 hour }, nil } // generateToken creates a new JWT token for the user func (s *AuthService) generateToken(user *models.User) (string, error) { // Create claims claims := jwt.MapClaims{ "user_id": user.ID, "username": user.Username, "email": user.Email, "role": user.Role, "exp": time.Now().Add(time.Hour * 1).Unix(), "iat": time.Now().Unix(), } // Create token token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // Sign token with secret key secretKey := []byte(s.getJWTSecret()) return token.SignedString(secretKey) } // GenerateTokenForUser generates a JWT token for a specific user func (s *AuthService) GenerateTokenForUser(user *models.User) (string, error) { // Create claims claims := jwt.MapClaims{ "user_id": user.ID, "username": user.Username, "email": user.Email, "role": user.Role, "exp": time.Now().Add(time.Hour * 1).Unix(), "iat": time.Now().Unix(), } // Create token token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // Sign token with secret key secretKey := []byte(s.getJWTSecret()) return token.SignedString(secretKey) } // ValidateToken validates the JWT token func (s *AuthService) ValidateToken(tokenString string) (*models.JWTClaims, error) { token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, errors.New("unexpected signing method") } return []byte(s.getJWTSecret()), nil }) if err != nil { return nil, err } if !token.Valid { return nil, errors.New("invalid token") } claims, ok := token.Claims.(jwt.MapClaims) if !ok { return nil, errors.New("invalid claims") } return &models.JWTClaims{ UserID: claims["user_id"].(string), Username: claims["username"].(string), Email: claims["email"].(string), Role: claims["role"].(string), }, nil } // getJWTSecret returns the JWT secret key func (s *AuthService) getJWTSecret() string { // In production, this should come from environment variables return "your-secret-key-change-this-in-production" } // RegisterUser registers a new user (for demo purposes) func (s *AuthService) RegisterUser(username, email, password, role string) error { if _, exists := s.users[username]; exists { return errors.New("username already exists") } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return err } s.users[username] = &models.User{ ID: string(rune(len(s.users) + 1)), Username: username, Email: email, Password: string(hashedPassword), Role: role, } return nil }