veza/veza-backend-api/internal/middleware/rbac_middleware.go
2025-12-03 20:29:37 +01:00

103 lines
2.7 KiB
Go

package middleware
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
)
// RoleChecker définit l'interface minimale pour vérifier les rôles et permissions
// Permet d'utiliser des mocks dans les tests sans modifier la signature publique
type RoleChecker interface {
HasRole(ctx context.Context, userID int64, roleName string) (bool, error)
HasPermission(ctx context.Context, userID int64, resource, action string) (bool, error)
}
// RequireRole crée un middleware qui exige qu'un utilisateur ait un rôle spécifique
func RequireRole(roleService RoleChecker, roleName string) gin.HandlerFunc {
return func(c *gin.Context) {
// Récupérer user_id du contexte (doit être défini par AuthMiddleware)
userIDInterface, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
c.Abort()
return
}
// Convertir user_id en int64
var userID int64
switch v := userIDInterface.(type) {
case int64:
userID = v
case int:
userID = int64(v)
case float64:
userID = int64(v)
default:
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid user id type"})
c.Abort()
return
}
// Vérifier si l'utilisateur a le rôle requis
hasRole, err := roleService.HasRole(c.Request.Context(), userID, roleName)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to check role"})
c.Abort()
return
}
if !hasRole {
c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
c.Abort()
return
}
c.Next()
}
}
// RequirePermission crée un middleware qui exige qu'un utilisateur ait une permission spécifique
func RequirePermission(roleService RoleChecker, resource, action string) gin.HandlerFunc {
return func(c *gin.Context) {
// Récupérer user_id du contexte (doit être défini par AuthMiddleware)
userIDInterface, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
c.Abort()
return
}
// Convertir user_id en int64
var userID int64
switch v := userIDInterface.(type) {
case int64:
userID = v
case int:
userID = int64(v)
case float64:
userID = int64(v)
default:
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid user id type"})
c.Abort()
return
}
// Vérifier si l'utilisateur a la permission requise
hasPermission, err := roleService.HasPermission(c.Request.Context(), userID, resource, action)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to check permission"})
c.Abort()
return
}
if !hasPermission {
c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
c.Abort()
return
}
c.Next()
}
}