Update JWT

This commit is contained in:
ahmadafriadi 2025-06-27 11:17:20 +07:00
parent 54aeb3568a
commit 1db200435e
12 changed files with 110 additions and 32 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Ignore environment config
.env

16
Dockerfile Normal file
View File

@ -0,0 +1,16 @@
# Dockerfile
FROM golang:1.24.4
WORKDIR /app
COPY go.mod ./
COPY go.sum ./
RUN go mod download
COPY . .
RUN go build -o main ./cmd/main.go
EXPOSE 3000
CMD ["./main"]

View File

@ -1,6 +1,7 @@
package api
import (
"BE-MiniERP/middlewares"
"BE-MiniERP/modules/auth"
"BE-MiniERP/modules/inventory"
"BE-MiniERP/modules/sales"
@ -10,6 +11,10 @@ import (
func SetupRoutes(app *fiber.App) {
auth.RegisterRoutes(app.Group("/auth"))
app.Use("/inventory", middlewares.JWTProtected())
app.Use("/sales", middlewares.JWTProtected())
inventory.RegisterRoutes(app.Group("/inventory"))
sales.RegisterRoutes(app.Group("/sales"))
}

View File

@ -4,12 +4,15 @@ import (
"log"
"BE-MiniERP/api"
"BE-MiniERP/config"
"BE-MiniERP/database" // pastikan ini sesuai dengan module di go.mod
"github.com/gofiber/fiber/v2"
)
func main() {
// Inisialisasi konfigurasi
config.InitConfig()
// Koneksi database
database.Connect()

View File

@ -1,15 +1,45 @@
package config
import "os"
import (
"log"
"os"
"github.com/joho/godotenv"
)
type Config struct {
DBUrl string
JWTSecret string
DBHost string
DBPort string
DBUser string
DBPassword string
DBName string
DBSSLMode string
}
func GetConfig() Config {
return Config{
DBUrl: os.Getenv("DB_URL"),
JWTSecret: os.Getenv("JWT_SECRET"),
var appConfig = &Config{}
func InitConfig() {
// Load .env file
err := godotenv.Load()
if err != nil {
log.Println("Warning: .env file not found, using system environment variables.")
}
// Load config from env
appConfig.JWTSecret = os.Getenv("JWT_SECRET")
appConfig.DBHost = os.Getenv("DB_HOST")
appConfig.DBPort = os.Getenv("DB_PORT")
appConfig.DBUser = os.Getenv("DB_USER")
appConfig.DBPassword = os.Getenv("DB_PASSWORD")
appConfig.DBName = os.Getenv("DB_NAME")
appConfig.DBSSLMode = os.Getenv("DB_SSLMODE")
if appConfig.JWTSecret == "" || appConfig.DBHost == "" {
log.Fatal("Required environment variables are missing")
}
}
func GetConfig() *Config {
return appConfig
}

View File

@ -7,7 +7,7 @@ CREATE TABLE users (
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE master_product_category (
CREATE TABLE product_categories (
id SERIAL PRIMARY KEY,
code VARCHAR(50),
name VARCHAR(100),

View File

@ -1,9 +1,11 @@
package database
import (
"BE-MiniERP/config"
auth_models "BE-MiniERP/modules/auth/models"
inventory_models "BE-MiniERP/modules/inventory/models"
sales_models "BE-MiniERP/modules/sales/models"
"fmt"
"log"
"gorm.io/driver/postgres"
@ -13,18 +15,22 @@ import (
var DB *gorm.DB
func Connect() {
dsn := "host=10.5.50.9 user=probindo password=Pr08ind0 dbname=erp port=5432 sslmode=disable"
cfg := config.GetConfig()
dsn := fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%s sslmode=%s",
cfg.DBHost, cfg.DBUser, cfg.DBPassword, cfg.DBName, cfg.DBPort, cfg.DBSSLMode,
)
var err error
DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to DB:", err)
}
// Auto migrate models
err = DB.AutoMigrate(
// Auth
&auth_models.User{},
// Inventory
&inventory_models.Product{},
&inventory_models.ProductCategory{},
&inventory_models.Collection{},
@ -34,8 +40,6 @@ func Connect() {
&inventory_models.ProductionOrder{},
&inventory_models.Warehouse{},
&inventory_models.StockMovement{},
// Sales
&sales_models.Customer{},
&sales_models.SalesOrder{},
&sales_models.SalesOrderItem{},

10
docker-compose.yml Normal file
View File

@ -0,0 +1,10 @@
version: "3.8"
services:
app:
build: .
container_name: be-minierp-container
ports:
- "8080:3000"
environment:
- DATABASE_URL=host=10.5.50.9 user=probindo password=Pr08ind0 dbname=erp port=5432 sslmode=disable

1
go.mod
View File

@ -14,6 +14,7 @@ require (
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/joho/godotenv v1.5.1
github.com/klauspost/compress v1.17.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect

2
go.sum
View File

@ -19,6 +19,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=

View File

@ -12,7 +12,9 @@ func JWTProtected() fiber.Handler {
return func(c *fiber.Ctx) error {
authHeader := c.Get("Authorization")
if authHeader == "" {
return c.SendStatus(fiber.StatusUnauthorized)
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"message": "Missing Authorization header",
})
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
@ -21,10 +23,19 @@ func JWTProtected() fiber.Handler {
})
if err != nil || !token.Valid {
return c.SendStatus(fiber.StatusUnauthorized)
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"message": "Invalid or expired token",
})
}
c.Locals("user", token.Claims)
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"message": "Invalid token claims",
})
}
c.Locals("user", claims)
return c.Next()
}
}

View File

@ -1,27 +1,21 @@
package service
import (
"BE-MiniERP/config"
"time"
"github.com/golang-jwt/jwt/v4"
)
var jwtKey = []byte("supersecret") // sebaiknya dari env
type Claims struct {
UserID uint `json:"user_id"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func GenerateJWT(userID uint, role string) (string, error) {
claims := &Claims{
UserID: userID,
Role: role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
},
claims := jwt.MapClaims{
"user_id": userID,
"role": role,
"exp": time.Now().Add(time.Hour * 1).Unix(), // expired dalam 1 jam
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtKey)
// INI PALING PENTING ⬇️
return token.SignedString([]byte(config.GetConfig().JWTSecret))
}