feat: 0.0.1
This commit is contained in:
146 files changed
+10444
No files matched your search
@@ -0,0 +1,139 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/FernandoJVideira/simple_bank/internal/auth"
|
||||
"github.com/FernandoJVideira/simple_bank/internal/config"
|
||||
db "github.com/FernandoJVideira/simple_bank/internal/db/sqlc"
|
||||
"github.com/FernandoJVideira/simple_bank/internal/security"
|
||||
)
|
||||
|
||||
type authService struct {
|
||||
store db.Store
|
||||
tokenMaker auth.Maker
|
||||
config config.Config
|
||||
}
|
||||
|
||||
// NewAuthService creates a new auth service
|
||||
func NewAuthService(store db.Store, tokenMaker auth.Maker, config config.Config) AuthService {
|
||||
return &authService{
|
||||
store: store,
|
||||
tokenMaker: tokenMaker,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *authService) Login(ctx context.Context, params LoginCredentials) (*LoginResponse, error) {
|
||||
// Get user from database
|
||||
user, err := s.store.GetUser(ctx, params.Username)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("user not found: %w", err)
|
||||
}
|
||||
|
||||
// Verify password
|
||||
err = security.CheckPassword(params.Password, user.HashedPassword)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("incorrect username or password: %w", err)
|
||||
}
|
||||
|
||||
// Create access token
|
||||
accessToken, accessPayload, err := s.tokenMaker.CreateToken(
|
||||
user.Username,
|
||||
user.Role,
|
||||
s.config.AuthTokenExp,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create access token: %w", err)
|
||||
}
|
||||
|
||||
// Create refresh token
|
||||
refreshToken, refreshPayload, err := s.tokenMaker.CreateToken(
|
||||
user.Username,
|
||||
user.Role,
|
||||
s.config.RefreshTokenExp,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create refresh token: %w", err)
|
||||
}
|
||||
|
||||
// Create session
|
||||
session, err := s.store.CreateSession(ctx, db.CreateSessionParams{
|
||||
ID: refreshPayload.ID,
|
||||
Username: user.Username,
|
||||
RefreshToken: refreshToken,
|
||||
UserAgent: params.UserAgent,
|
||||
ClientIp: params.ClientIP,
|
||||
IsBlocked: false,
|
||||
ExpiresAt: refreshPayload.ExpiredAt,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create session: %w", err)
|
||||
}
|
||||
|
||||
return &LoginResponse{
|
||||
SessionID: session.ID,
|
||||
AccessToken: accessToken,
|
||||
AccessTokenExpiresAt: accessPayload.ExpiredAt,
|
||||
RefreshToken: refreshToken,
|
||||
RefreshTokenExpiresAt: refreshPayload.ExpiredAt,
|
||||
User: user,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *authService) RenewAccessToken(ctx context.Context, params TokenRenewalRequest) (*TokenRenewalResponse, error) {
|
||||
// Verify refresh token
|
||||
refreshPayload, err := s.tokenMaker.VerifyToken(params.RefreshToken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid refresh token: %w", err)
|
||||
}
|
||||
|
||||
// Get session
|
||||
session, err := s.store.GetSession(ctx, refreshPayload.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("session not found: %w", err)
|
||||
}
|
||||
|
||||
// Validate session
|
||||
if err := s.validateSession(session, refreshPayload.Username, params.RefreshToken); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create new access token
|
||||
accessToken, accessPayload, err := s.tokenMaker.CreateToken(
|
||||
refreshPayload.Username,
|
||||
refreshPayload.Role,
|
||||
s.config.AuthTokenExp,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create access token: %w", err)
|
||||
}
|
||||
|
||||
return &TokenRenewalResponse{
|
||||
AccessToken: accessToken,
|
||||
AccessTokenExpiresAt: accessPayload.ExpiredAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// validateSession contains business rules for session validation
|
||||
func (s *authService) validateSession(session db.Session, username, refreshToken string) error {
|
||||
if session.IsBlocked {
|
||||
return fmt.Errorf("session is blocked")
|
||||
}
|
||||
|
||||
if session.Username != username {
|
||||
return fmt.Errorf("incorrect session user")
|
||||
}
|
||||
|
||||
if session.RefreshToken != refreshToken {
|
||||
return fmt.Errorf("mismatched session token")
|
||||
}
|
||||
|
||||
if time.Now().After(session.ExpiresAt) {
|
||||
return fmt.Errorf("session has expired")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user