Refactor added saving auth token to redis when successfully logged in
This commit is contained in:
@@ -13,3 +13,4 @@ API_MONGODB_URL=mongodb://mongodb:12345678@mongo-db:27017
|
|||||||
# EVENTBUS_URL=amqp://guest:guest@api-eventbus:5672
|
# EVENTBUS_URL=amqp://guest:guest@api-eventbus:5672
|
||||||
|
|
||||||
JWT_SECRET_KEY=SomeFancySecretAndRandomString
|
JWT_SECRET_KEY=SomeFancySecretAndRandomString
|
||||||
|
JWT_TOKEN_EXPIRE_TIME=1 # hours
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module git.ego.freeddns.org/egommerce/identity-service
|
|||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
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
|
git.ego.freeddns.org/egommerce/go-api-pkg v0.4.6
|
||||||
github.com/go-pg/migrations/v8 v8.1.0
|
github.com/go-pg/migrations/v8 v8.1.0
|
||||||
github.com/go-pg/pg/v10 v10.11.1
|
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/fiber/v2 v2.52.4
|
||||||
github.com/gofiber/jwt/v2 v2.2.7
|
github.com/gofiber/jwt/v2 v2.2.7
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
|
github.com/google/uuid v1.5.0
|
||||||
github.com/jackc/pgx/v5 v5.4.3
|
github.com/jackc/pgx/v5 v5.4.3
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,7 +22,6 @@ require (
|
|||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/go-pg/zerochecker v0.2.0 // indirect
|
github.com/go-pg/zerochecker v0.2.0 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.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/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
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.4 h1:yzPpumgtZeANRX3c74Y8/Z3s4vR6BKYceZhPLnLNNVY=
|
||||||
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/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 h1:1iZW+vkbv7fQusv/pMjtIM1QvJ+QQr3nyvuuajgHc80=
|
||||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.4.6/go.mod h1:5Ft8LCd0UXp5hHpvXRBCv9mCGikogFhL7LP2qit12JM=
|
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=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
|||||||
@@ -12,11 +12,15 @@ func (s *Server) LoginHandlerFn(c *fiber.Ctx) error {
|
|||||||
return s.Error(c, fiber.StatusBadRequest, "Error parsing input")
|
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)
|
token, err := authSrv.Login(data.Username, data.Password)
|
||||||
if err != nil {
|
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})
|
return c.JSON(&dto.AuthLoginResponseDTO{Token: token})
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ func (s *Server) RegisterHandlerFn(c *fiber.Ctx) error {
|
|||||||
return s.Error(c, fiber.StatusBadRequest, "Error parsing input")
|
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)
|
id, err := authSrv.Register(data.Email, data.Username, data.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,40 +3,55 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
db "git.ego.freeddns.org/egommerce/identity-service/pkg/database"
|
db "git.ego.freeddns.org/egommerce/identity-service/pkg/database"
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
AuthService *Auth
|
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() {
|
func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Auth struct {
|
type Auth struct {
|
||||||
db *pgxpool.Pool
|
db *pgxpool.Pool
|
||||||
|
cache *redis.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthService(db *pgxpool.Pool) *Auth {
|
func NewAuthService(db *pgxpool.Pool, cache *redis.Client) *Auth {
|
||||||
return &Auth{db: db}
|
return &Auth{
|
||||||
|
db: db,
|
||||||
|
cache: cache,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) Login(login, passwd string) (string, error) {
|
func (a *Auth) Login(login, passwd string) (string, error) {
|
||||||
if login == "admin" && passwd == "secret" { // FIXME hardcoded
|
var id string
|
||||||
token, err := JWTService.CreateToken()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
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 {
|
if err = db.IsDuplicatedRow(err); err != nil {
|
||||||
return "", errors.New("username/email is already taken")
|
return "", errors.New("username/email is already taken")
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errors.New("Failed to create new user: " + err.Error())
|
return "", errors.New("Failed to create new user: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return id, nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,24 +10,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tokenExpireTime int
|
tokenExpireTime time.Duration
|
||||||
tokenSecret []byte
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
tokenExpireTime, _ = strconv.Atoi(baseCnf.GetEnv("JWT_TOKEN_EXPIRE_TIME", "5"))
|
min, _ := strconv.Atoi(baseCnf.GetEnv("JWT_TOKEN_EXPIRE_TIME", "5"))
|
||||||
tokenSecret = []byte(baseCnf.GetEnv("JWT_SECRET_KEY", "B413IlIv9nKQfsMCXTE0Cteo4yHgUEfqaLfjg73sNlh")) // FIXME env: JWT_SECRET_KEY !!!
|
tokenExpireTime = time.Duration(int(time.Hour) * min)
|
||||||
|
|
||||||
JWTService = &JWT{tokenExpireTime, tokenSecret}
|
jwtSrv = &JWT{
|
||||||
|
tokenExpireTime,
|
||||||
|
[]byte(baseCnf.GetEnv("JWT_SECRET_KEY", "B413IlIv9nKQfsMCXTE0Cteo4yHgUEfqaLfjg73sNlh")),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type JWT struct {
|
type JWT struct {
|
||||||
tokenExpireTime int
|
tokenExpireTime time.Duration
|
||||||
tokenSecret []byte
|
tokenSecret []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *JWT) CreateToken() (string, error) {
|
func (s *JWT) CreateToken(id string) (string, error) {
|
||||||
claims := &jwt.StandardClaims{
|
claims := &jwt.StandardClaims{
|
||||||
|
Id: id,
|
||||||
ExpiresAt: time.Now().Add(time.Duration(s.tokenExpireTime) * time.Minute).Unix(),
|
ExpiresAt: time.Now().Add(time.Duration(s.tokenExpireTime) * time.Minute).Unix(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,3 +26,18 @@ func IsDuplicatedRow(err error) error {
|
|||||||
|
|
||||||
return nil
|
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
|
||||||
|
// }
|
||||||
|
|||||||
Reference in New Issue
Block a user