diff --git a/app/configs/configs.go b/app/configs/configs.go index eb537c8..7288bb1 100644 --- a/app/configs/configs.go +++ b/app/configs/configs.go @@ -2,6 +2,7 @@ package configs import ( "os" + "strconv" "sync" ) @@ -20,6 +21,11 @@ type DbConfig struct { DbIsMigrate bool } +type JwtConfig struct { + Secret string + Expired int +} + type RedisConfig struct { Host string Port string @@ -29,6 +35,7 @@ type RedisConfig struct { type Configs struct { Appconfig AppConfig Dbconfig DbConfig + Jwtconfig JwtConfig Redisconfig RedisConfig } @@ -38,6 +45,8 @@ var configs *Configs func GetInstance() *Configs { if configs == nil { lock.Lock() + JwtExpired, _ := strconv.Atoi(os.Getenv("JWT_EXPIRED_SECOND")) + configs = &Configs{ Appconfig: AppConfig{ Name: os.Getenv("APP_NAME"), @@ -52,6 +61,10 @@ func GetInstance() *Configs { Password: os.Getenv("DB_PASS"), DbIsMigrate: os.Getenv("DB_ISMIGRATE") == "true", }, + Jwtconfig: JwtConfig{ + Secret: os.Getenv("JWT_SECRET"), + Expired: int(JwtExpired), + }, Redisconfig: RedisConfig{ Host: os.Getenv("REDIS_HOST"), Port: os.Getenv("REDIS_PORT"), diff --git a/app/controllers/auth/auth.controller.go b/app/controllers/auth/auth.controller.go index b90276d..48a5744 100644 --- a/app/controllers/auth/auth.controller.go +++ b/app/controllers/auth/auth.controller.go @@ -3,6 +3,7 @@ package auth import ( "github.com/ajikamaludin/go-fiber-rest/app/models" userRepository "github.com/ajikamaludin/go-fiber-rest/app/repository/user" + "github.com/ajikamaludin/go-fiber-rest/pkg/jwtmanager" "github.com/ajikamaludin/go-fiber-rest/pkg/utils/constants" "github.com/ajikamaludin/go-fiber-rest/pkg/utils/validator" "github.com/gofiber/fiber/v2" @@ -35,11 +36,50 @@ func Login(c *fiber.Ctx) error { "error": err.Error(), }) } - // generate jwt token - // return token and user detail + + accessToken := jwtmanager.CreateToken(user) + + return c.Status(fiber.StatusOK).JSON(fiber.Map{ + "user": user, + "accessToken": accessToken, + "refreshToken": "", + }) +} + +func Register(c *fiber.Ctx) error { + userRequest := new(models.User) + + _ = c.BodyParser(&userRequest) + + errors := validator.ValidateRequest(userRequest) + if errors != nil { + return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{ + "status": constants.STATUS_FAIL, + "message": "request body mismatch", + "error": errors, + }) + } + + user := &models.User{ + Email: userRequest.Email, + Password: userRequest.Password, + } + err := userRepository.GetUserByEmail(userRequest.Email, user) + if err == nil { + return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{ + "status": constants.STATUS_FAIL, + "message": "email is already exists", + "error": "", + }) + } + + userRepository.CreateUser(user) + + accessToken := jwtmanager.CreateToken(user) + return c.Status(fiber.StatusOK).JSON(fiber.Map{ "user": user, - "accessToken": "", + "accessToken": accessToken, "refreshToken": "", }) } diff --git a/app/controllers/exception/exception.controller.go b/app/controllers/exception/exception.controller.go new file mode 100644 index 0000000..92cec2e --- /dev/null +++ b/app/controllers/exception/exception.controller.go @@ -0,0 +1,14 @@ +package exception + +import ( + "github.com/ajikamaludin/go-fiber-rest/pkg/utils/constants" + "github.com/gofiber/fiber/v2" +) + +func ExceptionNotFound(c *fiber.Ctx, err error) error { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ + "status": constants.STATUS_FAIL, + "message": "Not Found", + "err": err.Error(), + }) +} diff --git a/app/controllers/note/note.controller.go b/app/controllers/note/note.controller.go index fcca439..82415ff 100644 --- a/app/controllers/note/note.controller.go +++ b/app/controllers/note/note.controller.go @@ -69,9 +69,8 @@ func CreateNote(c *fiber.Ctx) error { } var note = models.Note{ - User_id: "1", - Title: noteRequest.Note, - Note: noteRequest.Title, + Title: noteRequest.Note, + Note: noteRequest.Title, } db.Create(¬e) diff --git a/app/middleware/jwt.go b/app/middleware/jwt.go deleted file mode 100644 index c870d7c..0000000 --- a/app/middleware/jwt.go +++ /dev/null @@ -1 +0,0 @@ -package middleware diff --git a/app/models/note.go b/app/models/note.go index cb999b7..45e1d5b 100644 --- a/app/models/note.go +++ b/app/models/note.go @@ -1,19 +1,14 @@ package models import ( - "fmt" - + "github.com/google/uuid" "gorm.io/gorm" ) type Note struct { gorm.Model - User_id string - Title string `validate:"required,min=3"` - Note string `validate:"required,min=3"` - Tag string -} - -func (note Note) MarshalBinary() ([]byte, error) { - return []byte(fmt.Sprintf("%v-%v", note.Title, note.Note)), nil + UserId uuid.UUID + Title string `validate:"required,min=3"` + Note string `validate:"required,min=3"` + Tag string } diff --git a/app/models/user.go b/app/models/user.go index b614af9..6415b8a 100644 --- a/app/models/user.go +++ b/app/models/user.go @@ -14,6 +14,7 @@ type User struct { DeletedAt gorm.DeletedAt `gorm:"index"` Email string `validate:"required,min=3,email"` Password string `validate:"required,min=3"` + Notes []Note } func (user *User) BeforeCreate(tx *gorm.DB) (err error) { diff --git a/app/repository/user/user.repository.go b/app/repository/user/user.repository.go index a790997..80d2b34 100644 --- a/app/repository/user/user.repository.go +++ b/app/repository/user/user.repository.go @@ -10,3 +10,17 @@ func GetUserByEmail(email string, user *models.User) (err error) { err = db.Where("email = ?", email).First(&user).Error return } + +func CreateUser(user *models.User) error { + db, err := gormdb.GetInstance() + if err != nil { + return err + } + + err = db.Create(&user).Error + if err != nil { + return err + } + + return nil +} diff --git a/go.mod b/go.mod index a896199..004ce35 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/gofiber/utils v0.0.10 // indirect + github.com/golang-jwt/jwt/v4 v4.4.2 // indirect github.com/gorilla/schema v1.1.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.12.1 // indirect @@ -39,6 +40,7 @@ require ( github.com/go-redis/redis/v8 v8.11.5 github.com/gofiber/fiber v1.14.6 github.com/gofiber/fiber/v2 v2.35.0 + github.com/gofiber/jwt/v3 v3.2.13 github.com/google/uuid v1.3.0 github.com/joho/godotenv v1.4.0 gorm.io/driver/postgres v1.3.8 diff --git a/go.sum b/go.sum index 8f1a290..265e8bb 100644 --- a/go.sum +++ b/go.sum @@ -33,9 +33,13 @@ github.com/gofiber/fiber v1.14.6 h1:QRUPvPmr8ijQuGo1MgupHBn8E+wW0IKqiOvIZPtV70o= github.com/gofiber/fiber v1.14.6/go.mod h1:Yw2ekF1YDPreO9V6TMYjynu94xRxZBdaa8X5HhHsjCM= github.com/gofiber/fiber/v2 v2.35.0 h1:ct+jKw8Qb24WEIZx3VV3zz9VXyBZL7mcEjNaqj3g0h0= github.com/gofiber/fiber/v2 v2.35.0/go.mod h1:tgCr+lierLwLoVHHO/jn3Niannv34WRkQETU8wiL9fQ= +github.com/gofiber/jwt/v3 v3.2.13 h1:csPOvGzMVYQpDHYkp8dvnj+IHD44/V5p4bhU/BJli9M= +github.com/gofiber/jwt/v3 v3.2.13/go.mod h1:gZMFgGuxJjGTVtQoytI69zP7iktlVbzv+nHCAS5UGDw= github.com/gofiber/utils v0.0.10 h1:3Mr7X7JdCUo7CWf/i5sajSaDmArEDtti8bM1JUVso2U= github.com/gofiber/utils v0.0.10/go.mod h1:9J5aHFUIjq0XfknT4+hdSMG6/jzfaAgCu4HEbWDeBlo= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/main.go b/main.go index 27d9a53..56eb2e1 100644 --- a/main.go +++ b/main.go @@ -31,7 +31,7 @@ func main() { // handle 404 notfound.Routes(app) - config := configs.GetInstance().Appconfig - listenPort := fmt.Sprintf(":%v", config.Port) - log.Fatal(app.Listen(listenPort)) + config := configs.GetInstance() + listen := fmt.Sprintf(":%v", config.Appconfig.Port) + log.Fatal(app.Listen(listen)) } diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go new file mode 100644 index 0000000..d802bbf --- /dev/null +++ b/pkg/jwtmanager/jwtmanager.go @@ -0,0 +1,24 @@ +package jwtmanager + +import ( + "time" + + "github.com/ajikamaludin/go-fiber-rest/app/configs" + "github.com/ajikamaludin/go-fiber-rest/app/models" + "github.com/golang-jwt/jwt/v4" +) + +func CreateToken(user *models.User) string { + configs := configs.GetInstance() + + claims := jwt.MapClaims{ + "user_id": user.ID, + "exp": time.Now().Add(time.Duration(configs.Jwtconfig.Expired) * time.Second).Unix(), + } + + unsignToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + token, _ := unsignToken.SignedString([]byte(configs.Jwtconfig.Secret)) + + return token +} diff --git a/routers/api/v1/routes.go b/routers/api/v1/routes.go index c0f3f87..89a1daf 100644 --- a/routers/api/v1/routes.go +++ b/routers/api/v1/routes.go @@ -1,15 +1,26 @@ package apiv1 import ( + "github.com/ajikamaludin/go-fiber-rest/app/configs" authController "github.com/ajikamaludin/go-fiber-rest/app/controllers/auth" + "github.com/ajikamaludin/go-fiber-rest/app/controllers/exception" noteController "github.com/ajikamaludin/go-fiber-rest/app/controllers/note" userController "github.com/ajikamaludin/go-fiber-rest/app/controllers/user" "github.com/gofiber/fiber/v2" + jwtware "github.com/gofiber/jwt/v3" ) func ApiRoutes(app *fiber.App) { route := app.Group("/api/v1") + route.Post("/auth/login", authController.Login) + route.Post("/auth/register", authController.Register) + + route = route.Group("/", jwtware.New(jwtware.Config{ + SigningKey: []byte(configs.GetInstance().Jwtconfig.Secret), + ErrorHandler: exception.ExceptionNotFound, + })) + route.Get("/notes", noteController.GetAllNotes) route.Post("/notes", noteController.CreateNote) route.Get("/notes/:id", noteController.GetNoteById) @@ -18,6 +29,4 @@ func ApiRoutes(app *fiber.App) { route.Post("/users", userController.CreateUser) route.Get("/users", userController.GetAllUsers) - - route.Post("/auth/login", authController.Login) }