package middleware import ( "net/http" "slices" "strings" "github.com/gin-gonic/gin" "github.com/nutcas3/telecom-platform/apps/api-server/internal/models" "github.com/nutcas3/telecom-platform/apps/api-server/internal/rbac" "github.com/nutcas3/telecom-platform/apps/api-server/internal/services" "gorm.io/gorm" ) // AuthMiddleware creates a JWT authentication middleware func AuthMiddleware(authService *services.AuthService) gin.HandlerFunc { return func(c *gin.Context) { // Get token from Authorization header authHeader := c.GetHeader("Authorization") if authHeader == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"}) c.Abort() return } // Extract token from "Bearer " format tokenParts := strings.Split(authHeader, " ") if len(tokenParts) != 2 || tokenParts[0] != "Bearer" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid authorization header format"}) c.Abort() return } token := tokenParts[1] // Validate token claims, err := authService.GetJWTService().ValidateToken(token) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) c.Abort() return } // Get user from database user, err := authService.GetUserByID(claims.UserID) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) c.Abort() return } // Store user and claims in context c.Set("user", user) c.Set("user_id", claims.UserID) c.Set("username", claims.Username) c.Set("role", claims.Role) c.Next() } } // RequirePermission creates a middleware that checks for specific permissions func RequirePermission(resource, action string) gin.HandlerFunc { return func(c *gin.Context) { user, exists := c.Get("user") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) c.Abort() return } // Get database from context (should be set by the main server) db, exists := c.Get("db") if !exists { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database not available"}) c.Abort() return } // Check permission if !user.(*models.User).HasPermission(db.(*gorm.DB), resource, action) { c.JSON(http.StatusForbidden, gin.H{"error": "Insufficient permissions"}) c.Abort() return } c.Next() } } // RequireCasbinPermission creates a middleware that checks for specific permissions using Casbin func RequireCasbinPermission(casbinService *rbac.CasbinService, resource, action string) gin.HandlerFunc { return func(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) c.Abort() return } allowed, err := casbinService.CheckPermission(c.Request.Context(), userID.(uint), resource, action) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check permissions"}) c.Abort() return } if !allowed { c.JSON(http.StatusForbidden, gin.H{"error": "Insufficient permissions"}) c.Abort() return } c.Next() } } // RequireRole creates a middleware that checks for specific roles (legacy, use RequireCasbinPermission for new features) func RequireRole(allowedRoles ...string) gin.HandlerFunc { return func(c *gin.Context) { role, exists := c.Get("role") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) c.Abort() return } userRole := role.(string) if slices.Contains(allowedRoles, userRole) { c.Next() return } c.JSON(http.StatusForbidden, gin.H{"error": "Insufficient role permissions"}) c.Abort() } } // OptionalAuthMiddleware creates an optional authentication middleware func OptionalAuthMiddleware(authService *services.AuthService) gin.HandlerFunc { return func(c *gin.Context) { // Get token from Authorization header authHeader := c.GetHeader("Authorization") if authHeader == "" { c.Next() return } // Extract token from "Bearer " format tokenParts := strings.Split(authHeader, " ") if len(tokenParts) != 2 || tokenParts[0] != "Bearer" { c.Next() return } token := tokenParts[1] // Validate token claims, err := authService.GetJWTService().ValidateToken(token) if err != nil { c.Next() return } // Get user from database user, err := authService.GetUserByID(claims.UserID) if err != nil { c.Next() return } // Store user and claims in context c.Set("user", user) c.Set("user_id", claims.UserID) c.Set("username", claims.Username) c.Set("role", claims.Role) c.Next() } }