added auth service to go backend
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"actatempus_backend/internal/domain/app_error"
|
||||
"actatempus_backend/internal/domain/repository"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
type InMemoryAuthRepository struct {
|
||||
secretKey string
|
||||
sessionCache map[string]string
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewInMemoryAuthRepository(secretKey string) repository.AuthRepository {
|
||||
return &InMemoryAuthRepository{
|
||||
secretKey: secretKey,
|
||||
sessionCache: make(map[string]string),
|
||||
mu: sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InMemoryAuthRepository) GenerateToken(ctx context.Context) func(userID string) E.Either[error, string] {
|
||||
return func(userID string) E.Either[error, string] {
|
||||
token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"userID": userID,
|
||||
"exp": time.Now().Add(24 * time.Hour).Unix(),
|
||||
}).SignedString([]byte(r.secretKey))
|
||||
|
||||
// add token to cache
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock() // unlock after function returns
|
||||
r.sessionCache[token] = userID
|
||||
|
||||
return E.TryCatch(
|
||||
token,
|
||||
err,
|
||||
func(e error) error {
|
||||
return app_error.NewInternalError(fmt.Errorf("could not generate token: %w", e))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InMemoryAuthRepository) ValidateToken(ctx context.Context) func(token string) E.Either[error, string] {
|
||||
return func(token string) E.Either[error, string] {
|
||||
// Separate value and error generation for TryCatch
|
||||
userID, err := func() (string, error) {
|
||||
parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, errors.New("invalid signing method")
|
||||
}
|
||||
return []byte(r.secretKey), nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if claims, ok := parsedToken.Claims.(jwt.MapClaims); ok && parsedToken.Valid {
|
||||
userID, ok := claims["userID"].(string)
|
||||
if !ok {
|
||||
return "", app_error.NewAuthError(fmt.Sprintf("invalid token claims"))
|
||||
}
|
||||
|
||||
// Check the cache
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
if cachedUserID, exists := r.sessionCache[token]; exists && cachedUserID == userID {
|
||||
return userID, nil
|
||||
}
|
||||
// print chache to see if it is working
|
||||
fmt.Println(r.sessionCache)
|
||||
return "", app_error.NewAuthError(fmt.Sprintf("token not found in cache"))
|
||||
}
|
||||
|
||||
return "", app_error.NewAuthError(fmt.Sprintf("invalid token"))
|
||||
}()
|
||||
|
||||
// Use TryCatch with separated value and error
|
||||
return E.TryCatch(
|
||||
userID,
|
||||
err,
|
||||
func(e error) error {
|
||||
return e
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InMemoryAuthRepository) RevokeToken(ctx context.Context) func(token string) E.Either[error, string] {
|
||||
return func(token string) E.Either[error, string] {
|
||||
// Separate value and error generation for TryCatch
|
||||
userID, err := func() (string, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if userID, exists := r.sessionCache[token]; exists {
|
||||
delete(r.sessionCache, token)
|
||||
return userID, nil
|
||||
}
|
||||
|
||||
return "", app_error.NewAuthError(fmt.Sprintf("token not found"))
|
||||
}()
|
||||
|
||||
// Use TryCatch with separated value and error
|
||||
return E.TryCatch(
|
||||
userID,
|
||||
err,
|
||||
func(e error) error {
|
||||
return e
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user