diff --git a/internal/services/auth_service.go b/internal/services/auth_service.go index b2dd068..da76f07 100644 --- a/internal/services/auth_service.go +++ b/internal/services/auth_service.go @@ -47,7 +47,14 @@ func (s *userService) Login(credentials dto.LoginDTO) (*dto.UserResponseWithToke return nil, err } - err = utils.SetData(credentials.Identifier, token, time.Hour*24) + sessionKey := fmt.Sprintf("session:%s", user.ID) + sessionData := map[string]interface{}{ + "userID": user.ID, + "roleID": user.RoleID, + "roleName": user.Role.RoleName, + } + + err = utils.SetJSONData(sessionKey, sessionData, time.Hour*24) if err != nil { return nil, err } diff --git a/middleware/auth_middleware.go b/middleware/auth_middleware.go new file mode 100644 index 0000000..eb07e10 --- /dev/null +++ b/middleware/auth_middleware.go @@ -0,0 +1,41 @@ +package middleware + +import ( + "os" + + "github.com/gofiber/fiber/v2" + "github.com/golang-jwt/jwt/v5" + "github.com/pahmiudahgede/senggoldong/utils" +) + +func AuthMiddleware(c *fiber.Ctx) error { + tokenString := c.Get("Authorization") + if tokenString == "" { + return utils.GenericErrorResponse(c, fiber.StatusUnauthorized, "Unauthorized: No token provided") + } + + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + return []byte(os.Getenv("SECRET_KEY")), nil + }) + + if err != nil || !token.Valid { + return utils.GenericErrorResponse(c, fiber.StatusUnauthorized, "Unauthorized: Invalid token") + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return utils.GenericErrorResponse(c, fiber.StatusUnauthorized, "Unauthorized: Invalid token claims") + } + + sessionKey := "session:" + claims["sub"].(string) + sessionData, err := utils.GetJSONData(sessionKey) + if err != nil { + return utils.GenericErrorResponse(c, fiber.StatusUnauthorized, "Session expired or invalid") + } + + c.Locals("userID", sessionData["userID"]) + c.Locals("roleID", sessionData["roleID"]) + c.Locals("roleName", sessionData["roleName"]) + + return c.Next() +} diff --git a/middleware/role_middleware.go b/middleware/role_middleware.go new file mode 100644 index 0000000..18c3aaf --- /dev/null +++ b/middleware/role_middleware.go @@ -0,0 +1,23 @@ +package middleware + +import ( + "github.com/gofiber/fiber/v2" + "github.com/pahmiudahgede/senggoldong/utils" +) + +func RoleMiddleware(allowedRoles ...string) fiber.Handler { + return func(c *fiber.Ctx) error { + roleID, exists := c.Locals("roleID").(string) + if !exists || roleID == "" { + return utils.GenericErrorResponse(c, fiber.StatusUnauthorized, "Unauthorized: Role not found in session") + } + + for _, role := range allowedRoles { + if role == roleID { + return c.Next() + } + } + + return utils.GenericErrorResponse(c, fiber.StatusForbidden, "Access Denied: You don't have permission to access this resource") + } +} diff --git a/utils/redis_caching.go b/utils/redis_caching.go index 9678b80..163b885 100644 --- a/utils/redis_caching.go +++ b/utils/redis_caching.go @@ -2,6 +2,7 @@ package utils import ( "context" + "encoding/json" "log" "time" @@ -10,7 +11,6 @@ import ( ) func SetData(key string, value interface{}, expiration time.Duration) error { - err := config.RedisClient.Set(context.Background(), key, value, expiration).Err() if err != nil { log.Printf("Error setting data to Redis: %v", err) @@ -21,7 +21,6 @@ func SetData(key string, value interface{}, expiration time.Duration) error { } func GetData(key string) (string, error) { - val, err := config.RedisClient.Get(context.Background(), key).Result() if err == redis.Nil { log.Printf("No data found for key: %s", key) @@ -35,7 +34,6 @@ func GetData(key string) (string, error) { } func DeleteData(key string) error { - err := config.RedisClient.Del(context.Background(), key).Err() if err != nil { log.Printf("Error deleting data from Redis: %v", err) @@ -46,7 +44,6 @@ func DeleteData(key string) error { } func SetDataWithExpire(key string, value interface{}, expiration time.Duration) error { - err := config.RedisClient.Set(context.Background(), key, value, expiration).Err() if err != nil { log.Printf("Error setting data with expiration to Redis: %v", err) @@ -57,7 +54,6 @@ func SetDataWithExpire(key string, value interface{}, expiration time.Duration) } func CheckKeyExists(key string) (bool, error) { - val, err := config.RedisClient.Exists(context.Background(), key).Result() if err != nil { log.Printf("Error checking if key exists in Redis: %v", err) @@ -65,3 +61,28 @@ func CheckKeyExists(key string) (bool, error) { } return val > 0, nil } + +func SetJSONData(key string, value interface{}, expiration time.Duration) error { + jsonData, err := json.Marshal(value) + if err != nil { + log.Printf("Error marshaling JSON data: %v", err) + return err + } + return SetData(key, jsonData, expiration) +} + +func GetJSONData(key string) (map[string]interface{}, error) { + val, err := GetData(key) + if err != nil || val == "" { + return nil, err + } + + var data map[string]interface{} + err = json.Unmarshal([]byte(val), &data) + if err != nil { + log.Printf("Error unmarshaling JSON data from Redis: %v", err) + return nil, err + } + + return data, nil +}