add service
This commit is contained in:
107
internal/service/auth.go
Normal file
107
internal/service/auth.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"smart-search-back/internal/model"
|
||||
"smart-search-back/internal/repository"
|
||||
"smart-search-back/pkg/crypto"
|
||||
"smart-search-back/pkg/errors"
|
||||
"smart-search-back/pkg/jwt"
|
||||
)
|
||||
|
||||
type authService struct {
|
||||
userRepo repository.UserRepository
|
||||
sessionRepo repository.SessionRepository
|
||||
jwtSecret string
|
||||
cryptoHelper *crypto.Crypto
|
||||
}
|
||||
|
||||
func NewAuthService(userRepo repository.UserRepository, sessionRepo repository.SessionRepository, jwtSecret, cryptoSecret string) AuthService {
|
||||
return &authService{
|
||||
userRepo: userRepo,
|
||||
sessionRepo: sessionRepo,
|
||||
jwtSecret: jwtSecret,
|
||||
cryptoHelper: crypto.NewCrypto(cryptoSecret),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *authService) Login(ctx context.Context, email, password, ip, userAgent string) (accessToken, refreshToken string, err error) {
|
||||
emailHash := s.cryptoHelper.EmailHash(email)
|
||||
|
||||
user, err := s.userRepo.FindByEmailHash(ctx, emailHash)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
passwordHash := crypto.PasswordHash(password)
|
||||
if user.PasswordHash != passwordHash {
|
||||
return "", "", errors.NewBusinessError(errors.AuthInvalidCredentials, "Invalid email or password")
|
||||
}
|
||||
|
||||
accessToken, err = jwt.GenerateAccessToken(user.ID, s.jwtSecret)
|
||||
if err != nil {
|
||||
return "", "", errors.NewInternalError(errors.InternalError, "failed to generate access token", err)
|
||||
}
|
||||
|
||||
refreshToken, err = jwt.GenerateRefreshToken(user.ID, s.jwtSecret)
|
||||
if err != nil {
|
||||
return "", "", errors.NewInternalError(errors.InternalError, "failed to generate refresh token", err)
|
||||
}
|
||||
|
||||
session := &model.Session{
|
||||
UserID: user.ID,
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
IP: ip,
|
||||
UserAgent: userAgent,
|
||||
ExpiresAt: time.Now().Add(30 * 24 * time.Hour),
|
||||
}
|
||||
|
||||
if err := s.sessionRepo.Create(ctx, session); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return accessToken, refreshToken, nil
|
||||
}
|
||||
|
||||
func (s *authService) Refresh(ctx context.Context, refreshToken string) (string, error) {
|
||||
session, err := s.sessionRepo.FindByRefreshToken(ctx, refreshToken)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
newAccessToken, err := jwt.GenerateAccessToken(session.UserID, s.jwtSecret)
|
||||
if err != nil {
|
||||
return "", errors.NewInternalError(errors.InternalError, "failed to generate access token", err)
|
||||
}
|
||||
|
||||
if err := s.sessionRepo.UpdateAccessToken(ctx, refreshToken, newAccessToken); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return newAccessToken, nil
|
||||
}
|
||||
|
||||
func (s *authService) Validate(ctx context.Context, accessToken string) (int, error) {
|
||||
claims, err := jwt.ValidateToken(accessToken, s.jwtSecret)
|
||||
if err != nil {
|
||||
return 0, errors.NewBusinessError(errors.AuthInvalidToken, "Invalid or expired token")
|
||||
}
|
||||
|
||||
if claims.Type != "access" {
|
||||
return 0, errors.NewBusinessError(errors.AuthInvalidToken, "Token is not an access token")
|
||||
}
|
||||
|
||||
userID, err := jwt.GetUserIDFromToken(accessToken, s.jwtSecret)
|
||||
if err != nil {
|
||||
return 0, errors.NewBusinessError(errors.AuthInvalidToken, "Invalid user ID in token")
|
||||
}
|
||||
|
||||
return userID, nil
|
||||
}
|
||||
|
||||
func (s *authService) Logout(ctx context.Context, refreshToken string) error {
|
||||
return s.sessionRepo.Revoke(ctx, refreshToken)
|
||||
}
|
||||
Reference in New Issue
Block a user