From dc28f975622f5b4a46729440b9a7a93b31374630 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 4 Jan 2024 17:57:30 +0300 Subject: [PATCH] add auth client --- .env | 5 +- internal/adapters/client/auth.go | 68 +++++++++++++++++++ internal/app/app.go | 2 + .../recovery/recovery_controller.go | 2 +- internal/initialize/{mail.go => clients.go} | 8 +++ internal/initialize/config.go | 1 + internal/models/auth.go | 11 +++ internal/services/recovery_service.go | 19 ++++-- 8 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 internal/adapters/client/auth.go rename internal/initialize/{mail.go => clients.go} (74%) create mode 100644 internal/models/auth.go diff --git a/.env b/.env index 19032cb..8ce3512 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ # General application settings APP_NAME=codeword HTTP_HOST="localhost" -HTTP_PORT="8000" +HTTP_PORT="8080" # MongoDB settings MONGO_HOST="127.0.0.1" @@ -33,4 +33,5 @@ SMTP_API_KEY="P0YsjUB137upXrr1NiJefHmXVKW1hmBWlpev" SMTP_SENDER="noreply@mailing.pena.digital" # URL settings -DEFAULT_REDIRECTION_URL = "def.url" \ No newline at end of file +DEFAULT_REDIRECTION_URL = "def.url" +AUTH_REFRESH_URL = "http://localhost:8000/auth/refresh" \ No newline at end of file diff --git a/internal/adapters/client/auth.go b/internal/adapters/client/auth.go new file mode 100644 index 0000000..7f501a5 --- /dev/null +++ b/internal/adapters/client/auth.go @@ -0,0 +1,68 @@ +package client + +import ( + "codeword/internal/models" + "encoding/json" + "fmt" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" +) + +type AuthClientDeps struct { + AuthUrl string + FiberClient *fiber.Client + Logger *zap.Logger +} + +type AuthClient struct { + deps AuthClientDeps +} + +func NewAuthClient(deps AuthClientDeps) *AuthClient { + if deps.FiberClient == nil { + deps.FiberClient = fiber.AcquireClient() + } + return &AuthClient{ + deps: deps, + } +} + +func (a *AuthClient) RefreshAuthToken(userID, signature string) (*models.RefreshResponse, error) { + body := models.AuthRequestBody{ + UserID: userID, + Signature: signature, + } + + bodyBytes, err := json.Marshal(body) + if err != nil { + a.deps.Logger.Error("Failed to encode request body", zap.Error(err)) + return nil, err + } + + agent := a.deps.FiberClient.Post(a.deps.AuthUrl) + agent.Set("Content-Type", "application/json").Body(bodyBytes) + //todo надо что-то придумать с авторизаиционными токенами + agent.Set("Authorization", "Bearer "+"123") + + statusCode, resBody, errs := agent.Bytes() + if len(errs) > 0 { + for _, err := range errs { + a.deps.Logger.Error("Error in refresh auth token request", zap.Error(err)) + } + return nil, fmt.Errorf("request failed: %v", errs) + } + + if statusCode != fiber.StatusOK { + errorMessage := fmt.Sprintf("received an incorrect response from the authentication service: %d", statusCode) + a.deps.Logger.Error(errorMessage, zap.Int("status", statusCode)) + return nil, fmt.Errorf(errorMessage) + } + + var tokens models.RefreshResponse + if err := json.Unmarshal(resBody, &tokens); err != nil { + a.deps.Logger.Error("failed to unmarshal auth service response", zap.Error(err)) + return nil, err + } + + return &tokens, nil +} diff --git a/internal/app/app.go b/internal/app/app.go index 1f40308..5c33226 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -27,12 +27,14 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { codewordRepo := repository.NewCodewordRepository(repository.Deps{Rdb: rdb, Mdb: mdb.Collection("codeword")}) userRepo := repository.NewUserRepository(repository.Deps{Rdb: nil, Mdb: mdb.Collection("users")}) recoveryEmailSender := initialize.InitializeRecoveryEmailSender(cfg, logger) + authClient := initialize.InitializeAuthClient(cfg, logger) recoveryService := services.NewRecoveryService(services.Deps{ Logger: logger, CodewordRepository: codewordRepo, UserRepository: userRepo, Encrypt: encrypt, + AuthClient: authClient, }) recoveryController := controller.NewRecoveryController(logger, recoveryService, cfg.DefaultRedirectionURL) diff --git a/internal/controller/recovery/recovery_controller.go b/internal/controller/recovery/recovery_controller.go index bf16b61..9d54350 100644 --- a/internal/controller/recovery/recovery_controller.go +++ b/internal/controller/recovery/recovery_controller.go @@ -86,7 +86,7 @@ func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error { return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Recovery link expired"}) } - tokens, err := r.service.ExchangeForTokens(record.UserID) + tokens, err := r.service.ExchangeForTokens(record.UserID, record.Sign) if err != nil { r.logger.Error("Failed to exchange recovery link for tokens", zap.Error(err)) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) diff --git a/internal/initialize/mail.go b/internal/initialize/clients.go similarity index 74% rename from internal/initialize/mail.go rename to internal/initialize/clients.go index dcdf3c0..0278933 100644 --- a/internal/initialize/mail.go +++ b/internal/initialize/clients.go @@ -21,3 +21,11 @@ func InitializeRecoveryEmailSender(cfg Config, logger *zap.Logger) *client.Recov CodewordPort: cfg.HTTPPort, }) } + +func InitializeAuthClient(cfg Config, logger *zap.Logger) *client.AuthClient { + return client.NewAuthClient(client.AuthClientDeps{ + AuthUrl: cfg.AuthURL, + Logger: logger, + FiberClient: &fiber.Client{}, + }) +} diff --git a/internal/initialize/config.go b/internal/initialize/config.go index b51bc54..deca1bc 100644 --- a/internal/initialize/config.go +++ b/internal/initialize/config.go @@ -30,6 +30,7 @@ type Config struct { SmtpApiKey string `env:"SMTP_API_KEY"` SmtpSender string `env:"SMTP_SENDER"` DefaultRedirectionURL string `env:"DEFAULT_REDIRECTION_URL"` + AuthURL string `env:"AUTH_REFRESH_URL"` } func LoadConfig() (*Config, error) { diff --git a/internal/models/auth.go b/internal/models/auth.go new file mode 100644 index 0000000..a159a74 --- /dev/null +++ b/internal/models/auth.go @@ -0,0 +1,11 @@ +package models + +type AuthRequestBody struct { + UserID string `json:"userId"` + Signature string `json:"signature"` +} + +type RefreshResponse struct { + AccessToken string `json:"accessToken"` + RefreshToken string `json:"refreshToken"` +} diff --git a/internal/services/recovery_service.go b/internal/services/recovery_service.go index 10c730f..c342b27 100644 --- a/internal/services/recovery_service.go +++ b/internal/services/recovery_service.go @@ -1,6 +1,7 @@ package services import ( + "codeword/internal/adapters/client" "codeword/internal/models" "codeword/internal/utils/encrypt" "context" @@ -24,6 +25,7 @@ type Deps struct { CodewordRepository CodewordRepository UserRepository UserRepository Encrypt *encrypt.Encrypt + AuthClient *client.AuthClient } type RecoveryService struct { @@ -31,6 +33,7 @@ type RecoveryService struct { repositoryCodeword CodewordRepository repositoryUser UserRepository encrypt *encrypt.Encrypt + authClient *client.AuthClient } func NewRecoveryService(deps Deps) *RecoveryService { @@ -39,6 +42,7 @@ func NewRecoveryService(deps Deps) *RecoveryService { repositoryCodeword: deps.CodewordRepository, repositoryUser: deps.UserRepository, encrypt: deps.Encrypt, + authClient: deps.AuthClient, } } @@ -117,8 +121,15 @@ func (s *RecoveryService) GetRecoveryRecord(ctx context.Context, key string) (*m return req, nil } -// ExchangeForTokens обменивает ссылку восстановления на токены используя сервис аутентификации. -func (s *RecoveryService) ExchangeForTokens(userID string) (map[string]string, error) { - // TODO - return nil, nil +func (s *RecoveryService) ExchangeForTokens(userID string, signature string) (map[string]string, error) { + tokens, err := s.authClient.RefreshAuthToken(userID, signature) + if err != nil { + s.logger.Error("Failed to refresh auth token", zap.Error(err)) + return nil, err + } + + return map[string]string{ + "accessToken": tokens.AccessToken, + "refreshToken": tokens.RefreshToken, + }, nil }