Membuat middleware menggunahkan JWT(JSON Web Token) di Gofiber

Konsep JWT (JSON Web Token)

JWT adalah metode yang digunakan untuk mengamankan komunikasi antara client dan server dengan cara membuat token yang berisi klaim-klaim tertentu, seperti user ID atau email. Token ini kemudian dikirim bersama setiap permintaan untuk memverifikasi identitas pengguna.

Langkah-langkah Menggunakan JWT dengan github.com/dgrijalva/jwt-go

  1. Install Package JWT: Jalankan perintah berikut untuk menginstall paket jwt-go:

    go get github.com/dgrijalva/jwt-go
  2. Setup Environment Variables: Tambahkan variabel lingkungan untuk menyimpan kunci rahasia JWT. Buat file .env dan tambahkan:

    SECRETKEY=your_secret_key_here
  3. Helper JWT: Buat helper untuk menghasilkan token JWT.

    // src/helpers/jwt.go
    
    package helpers
    
    import (
        "time"
    
        "github.com/dgrijalva/jwt-go"
    )
    
    func GenerateToken(secretKey, email string) (string, error) {
        token := jwt.New(jwt.SigningMethodHS256)
        claims := token.Claims.(jwt.MapClaims)
        claims["email"] = email
        claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
        return token.SignedString([]byte(secretKey))
    }
  4. Middleware JWT: Buat middleware untuk memeriksa validitas token JWT.

    // src/middlewares/jwt.go
    
    package middlewares
    
    import (
        "fmt"
        "os"
        "strings"
    
        "github.com/dgrijalva/jwt-go"
        "github.com/gofiber/fiber/v2"
    )
    
    func ExtractToken(c *fiber.Ctx) string {
        bearerToken := c.Get("Authorization")
        if strings.HasPrefix(bearerToken, "Bearer ") {
            return strings.TrimPrefix(bearerToken, "Bearer ")
        }
        return ""
    }
    
    func JwtMiddleware() fiber.Handler {
        secretKey := os.Getenv("SECRETKEY")
        return func(c *fiber.Ctx) error {
            tokenString := ExtractToken(c)
            if tokenString == "" {
                return c.Status(fiber.StatusUnauthorized)
                .JSON(fiber.Map{"error": "Unauthorized"})
            }
    
            _, err := jwt.Parse(tokenString, func(token *jwt.Token) 
            (interface{}, error) {
                if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                    return nil, fmt.Errorf("unexpected signing method: %v", 
                    token.Header["alg"])
                }
                return []byte(secretKey), nil
            })
    
            if err != nil {
                return c.Status(fiber.StatusUnauthorized)
                .JSON(fiber.Map{"error": "Unauthorized"})
            }
    
            return c.Next()
        }
    }
  5. Model User: Buat model untuk user.

    // src/models/Users.go
    
    package models
    
    import (
        "gofiber/src/configs"
    
        "gorm.io/gorm"
    )
    
    type User struct {
        gorm.Model
        Email    string `json:"email"`
        Password string `json:"password"`
    }
    
    func PostUser(user *User) error {
        return configs.DB.Create(user).Error
    }
    
    func FindEmail(email string) (*User, error) {
        var user User
        result := configs.DB.Where("email = ?", email).First(&user)
        return &user, result.Error
    }
  6. Controller User: Buat controller untuk registrasi dan login user.

    // src/controllers/UserController.go
    
    package controllers
    
    import (
        "gofiber/src/helpers"
        "gofiber/src/models"
        "os"
    
        "github.com/gofiber/fiber/v2"
        "golang.org/x/crypto/bcrypt"
    )
    
    func RegisterUser(c *fiber.Ctx) error {
        var user models.User
        if err := c.BodyParser(&user); err != nil {
            return c.Status(fiber.StatusBadRequest)
            .JSON(fiber.Map{"error": "Failed to parse request body"})
        }
    
        hashPassword, _ := bcrypt.GenerateFromPassword([]byte(user.Password), 
        bcrypt.DefaultCost)
        user.Password = string(hashPassword)
    
        if err := models.PostUser(&user); err != nil {
            return c.Status(fiber.StatusInternalServerError)
            .JSON(fiber.Map{"error": "Failed to create user"})
        }
    
        return c.Status(fiber.StatusCreated)
        .JSON(fiber.Map{"message": "Register successfully"})
    }
    
    func LoginUser(c *fiber.Ctx) error {
        var input models.User
        if err := c.BodyParser(&input); err != nil {
            return c.Status(fiber.StatusBadRequest)
            .JSON(fiber.Map{"error": "Failed to parse request body"})
        }
    
        user, err := models.FindEmail(input.Email)
        if err != nil {
            return c.Status(fiber.StatusNotFound)
            .JSON(fiber.Map{"message": "Email not found"})
        }
    
        if err := bcrypt.CompareHashAndPassword([]byte(user.Password), 
        []byte(input.Password)); err != nil {
            return c.Status(fiber.StatusUnauthorized)
            .JSON(fiber.Map{"message": "Invalid password"})
        }
    
        token, err := helpers.GenerateToken(os.Getenv("SECRETKEY"), user.Email)
        if err != nil {
            return c.Status(fiber.StatusInternalServerError)
            .JSON(fiber.Map{"error": "Failed to generate token"})
        }
    
        return c.JSON(fiber.Map{"message": "Login successfully", "token": token})
    }
  7. Router: Tambahkan rute untuk registrasi dan login user.

    // src/routes/main.go
    
    package routes
    
    import (
        "gofiber/src/controllers"
        "gofiber/src/middlewares"
    
        "github.com/gofiber/fiber/v2"
    )
    
    func Router(app *fiber.App) {
        // Product routes
        app.Get("/products", controllers.GetAllProducts)
        app.Get("/product/:id", controllers.GetProductById)
        app.Post("/product", controllers.CreateProduct)
        app.Put("/product/:id", controllers.UpdateProduct)
        app.Delete("/product/:id", controllers.DeleteProduct)
    
        // Category routes
        app.Get("/categories", middlewares.JwtMiddleware(), 
                controllers.GetAllCategories)
        app.Get("/category/:id", controllers.GetCategoryById)
        app.Post("/category", controllers.CreateCategory)
        app.Put("/category/:id", controllers.UpdateCategory)
        app.Delete("/category/:id", controllers.DeleteCategory)
    
        // User routes
        app.Post("/register", controllers.RegisterUser)
        app.Post("/login", controllers.LoginUser)
    }
  8. Migrasi Database: Tambahkan migrasi untuk model User.

    // src/helpers/migration.go
    
    package helpers
    
    import (
        "gofiber/src/configs"
        "gofiber/src/models"
    )
    
    func Migration() {
        configs.DB.AutoMigrate(&models.Product{}, &models.Category{}, &models.User{})
    }

Dengan mengikuti langkah-langkah di atas, Anda dapat mengimplementasikan keamanan JWT untuk autentikasi dan menambahkan header keamanan menggunakan Helmet untuk meningkatkan keamanan aplikasi Fiber Anda.

Sumber : Dokumentasi

Last updated