diff --git a/deploy/.env.dist b/deploy/.env.dist index b4d14c1..d3617cf 100644 --- a/deploy/.env.dist +++ b/deploy/.env.dist @@ -13,3 +13,4 @@ API_MONGODB_URL=mongodb://mongodb:12345678@mongo-db:27017 # EVENTBUS_URL=amqp://guest:guest@api-eventbus:5672 JWT_SECRET_KEY=SomeFancySecretAndRandomString +JWT_TOKEN_EXPIRE_TIME=1 # hours diff --git a/src/go.mod b/src/go.mod index 842369e..d9b24b7 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,7 +3,7 @@ module git.ego.freeddns.org/egommerce/identity-service go 1.18 require ( - git.ego.freeddns.org/egommerce/api-entities v0.3.3 + git.ego.freeddns.org/egommerce/api-entities v0.3.4 git.ego.freeddns.org/egommerce/go-api-pkg v0.4.6 github.com/go-pg/migrations/v8 v8.1.0 github.com/go-pg/pg/v10 v10.11.1 @@ -11,6 +11,7 @@ require ( github.com/gofiber/fiber/v2 v2.52.4 github.com/gofiber/jwt/v2 v2.2.7 github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/google/uuid v1.5.0 github.com/jackc/pgx/v5 v5.4.3 ) @@ -21,7 +22,6 @@ require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-pg/zerochecker v0.2.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/google/uuid v1.5.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect diff --git a/src/go.sum b/src/go.sum index 62d5132..5a61f31 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,6 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -git.ego.freeddns.org/egommerce/api-entities v0.3.3 h1:oH2lFpsGPKViXKlHIypnI/oQxWupWTkzbFPITebuDqo= -git.ego.freeddns.org/egommerce/api-entities v0.3.3/go.mod h1:IqynARw+06GOm4eZGZuepmbi7bUxWBnOB4jd5cI7jf8= +git.ego.freeddns.org/egommerce/api-entities v0.3.4 h1:yzPpumgtZeANRX3c74Y8/Z3s4vR6BKYceZhPLnLNNVY= +git.ego.freeddns.org/egommerce/api-entities v0.3.4/go.mod h1:IqynARw+06GOm4eZGZuepmbi7bUxWBnOB4jd5cI7jf8= git.ego.freeddns.org/egommerce/go-api-pkg v0.4.6 h1:1iZW+vkbv7fQusv/pMjtIM1QvJ+QQr3nyvuuajgHc80= git.ego.freeddns.org/egommerce/go-api-pkg v0.4.6/go.mod h1:5Ft8LCd0UXp5hHpvXRBCv9mCGikogFhL7LP2qit12JM= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= diff --git a/src/internal/server/login_handler.go b/src/internal/server/login_handler.go index f14108d..a06717d 100644 --- a/src/internal/server/login_handler.go +++ b/src/internal/server/login_handler.go @@ -12,11 +12,15 @@ func (s *Server) LoginHandlerFn(c *fiber.Ctx) error { return s.Error(c, fiber.StatusBadRequest, "Error parsing input") } - authSrv := service.NewAuthService(s.GetDatabase()) + authSrv := service.NewAuthService(s.GetDatabase(), s.GetCache()) token, err := authSrv.Login(data.Username, data.Password) if err != nil { - return fiber.NewError(fiber.StatusUnauthorized) + if err == service.ErrUnableToCacheToken { + return s.Error(c, fiber.StatusInternalServerError, err.Error()) + } + + return s.Error(c, fiber.StatusBadRequest, err.Error()) } return c.JSON(&dto.AuthLoginResponseDTO{Token: token}) diff --git a/src/internal/server/register_handler.go b/src/internal/server/register_handler.go index 419d167..4b47b4d 100644 --- a/src/internal/server/register_handler.go +++ b/src/internal/server/register_handler.go @@ -12,7 +12,7 @@ func (s *Server) RegisterHandlerFn(c *fiber.Ctx) error { return s.Error(c, fiber.StatusBadRequest, "Error parsing input") } - authSrv := service.NewAuthService(s.GetDatabase()) + authSrv := service.NewAuthService(s.GetDatabase(), s.GetCache()) id, err := authSrv.Register(data.Email, data.Username, data.Password) if err != nil { diff --git a/src/internal/service/auth.go b/src/internal/service/auth.go index 0862a54..2f93bf0 100644 --- a/src/internal/service/auth.go +++ b/src/internal/service/auth.go @@ -3,40 +3,55 @@ package service import ( "context" "errors" + "fmt" db "git.ego.freeddns.org/egommerce/identity-service/pkg/database" + "github.com/go-redis/redis/v8" "github.com/jackc/pgx/v5/pgxpool" ) var ( AuthService *Auth - JWTService *JWT + jwtSrv *JWT - ErrLoginIncorrect = errors.New("login incorrect") + ErrLoginIncorrect = errors.New("login incorrect") + ErrUnableToCacheToken = errors.New("unable to save token in cache") ) func init() { } type Auth struct { - db *pgxpool.Pool + db *pgxpool.Pool + cache *redis.Client } -func NewAuthService(db *pgxpool.Pool) *Auth { - return &Auth{db: db} +func NewAuthService(db *pgxpool.Pool, cache *redis.Client) *Auth { + return &Auth{ + db: db, + cache: cache, + } } func (a *Auth) Login(login, passwd string) (string, error) { - if login == "admin" && passwd == "secret" { // FIXME hardcoded - token, err := JWTService.CreateToken() - if err != nil { - return "", err - } + var id string - return token, nil + sql := `SELECT id FROM identity.users WHERE username=$1 AND password=$2 LIMIT 1` + err := a.db.QueryRow(context.Background(), sql, login, passwd).Scan(&id) + if err != nil { + // if err = db.NoRowsInQuerySet(err); err != nil { // FIXME NoRowsInQuerySet error detect + // return "", errors.New("no user found") + // } + + return "", ErrLoginIncorrect } - return "", ErrLoginIncorrect + token, _ := jwtSrv.CreateToken(id) + if err = a.saveTokenToCache(token, id); err != nil { + return "", ErrUnableToCacheToken + } + + return token, nil } func (a *Auth) Register(email, login, passwd string) (string, error) { @@ -48,8 +63,18 @@ func (a *Auth) Register(email, login, passwd string) (string, error) { if err = db.IsDuplicatedRow(err); err != nil { return "", errors.New("username/email is already taken") } + return "", errors.New("Failed to create new user: " + err.Error()) } return id, nil } + +func (a *Auth) saveTokenToCache(token, id string) error { + res := a.cache.Set(context.Background(), "auth:token:"+id, token, tokenExpireTime) + if err := res.Err(); err != nil { + fmt.Println("failed to save token in redis: ", err.Error()) + } + + return nil +} diff --git a/src/internal/service/jwt.go b/src/internal/service/jwt.go index 080b25e..4768255 100644 --- a/src/internal/service/jwt.go +++ b/src/internal/service/jwt.go @@ -10,24 +10,27 @@ import ( ) var ( - tokenExpireTime int - tokenSecret []byte + tokenExpireTime time.Duration ) func init() { - tokenExpireTime, _ = strconv.Atoi(baseCnf.GetEnv("JWT_TOKEN_EXPIRE_TIME", "5")) - tokenSecret = []byte(baseCnf.GetEnv("JWT_SECRET_KEY", "B413IlIv9nKQfsMCXTE0Cteo4yHgUEfqaLfjg73sNlh")) // FIXME env: JWT_SECRET_KEY !!! + min, _ := strconv.Atoi(baseCnf.GetEnv("JWT_TOKEN_EXPIRE_TIME", "5")) + tokenExpireTime = time.Duration(int(time.Hour) * min) - JWTService = &JWT{tokenExpireTime, tokenSecret} + jwtSrv = &JWT{ + tokenExpireTime, + []byte(baseCnf.GetEnv("JWT_SECRET_KEY", "B413IlIv9nKQfsMCXTE0Cteo4yHgUEfqaLfjg73sNlh")), + } } type JWT struct { - tokenExpireTime int + tokenExpireTime time.Duration tokenSecret []byte } -func (s *JWT) CreateToken() (string, error) { +func (s *JWT) CreateToken(id string) (string, error) { claims := &jwt.StandardClaims{ + Id: id, ExpiresAt: time.Now().Add(time.Duration(s.tokenExpireTime) * time.Minute).Unix(), } diff --git a/src/pkg/database/connect.go b/src/pkg/database/connect.go index 1e64d92..408f9d1 100644 --- a/src/pkg/database/connect.go +++ b/src/pkg/database/connect.go @@ -26,3 +26,18 @@ func IsDuplicatedRow(err error) error { return nil } + +// FIXME get an idea how this func should work +// func NoRowsInQuerySet(err error) error { +// var pgErr *pgconn.PgError + +// if errors.As(err, &pgErr) { +// fmt.Println("pgerr:", pgErr.Code) +// return errors.New("no rows selected") +// } +// // if err == pgconn. { +// // fmt.Println("No rows were found.") +// // } + +// return nil +// }