mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
upload
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"fotbal-club/internal/config"
|
||||
"fotbal-club/internal/models"
|
||||
"fotbal-club/pkg/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// JWTAuth is a middleware that checks for a valid JWT token
|
||||
func JWTAuth(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// Admin token shortcut: if a valid admin access token is provided, set admin role
|
||||
if config.AppConfig != nil && config.AppConfig.AdminAccessToken != "" {
|
||||
header := c.GetHeader("X-Admin-Token")
|
||||
if header != "" && header == config.AppConfig.AdminAccessToken {
|
||||
c.Set("userRole", "admin")
|
||||
c.Set("user", &models.User{Role: "admin"})
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
}
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
var tokenString string
|
||||
if authHeader != "" {
|
||||
// Extract the token from the header (format: "Bearer <token>")
|
||||
tokenParts := strings.Split(authHeader, " ")
|
||||
if len(tokenParts) == 2 && tokenParts[0] == "Bearer" {
|
||||
tokenString = tokenParts[1]
|
||||
} else {
|
||||
// If header present but malformed, reject early
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid authorization header format"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Fallback: try HttpOnly cookie set by server
|
||||
if cookie, err := c.Request.Cookie("auth_token"); err == nil {
|
||||
tokenString = cookie.Value
|
||||
} else {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header or auth cookie is required"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
claims, err := utils.ParseJWT(tokenString)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Check if user exists
|
||||
var user models.User
|
||||
if err := db.First(&user, claims.UserID).Error; err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Add user information to the context
|
||||
c.Set("user", &user)
|
||||
// Also expose parsed JWT claims for helpers/utilities
|
||||
c.Set("claims", claims)
|
||||
c.Set("userID", user.ID)
|
||||
c.Set("userRole", user.Role)
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// DevBypass checks for special dev header and grants admin role when not in production
|
||||
func DevBypass() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if config.AppConfig != nil && config.AppConfig.AppEnv != "production" {
|
||||
if strings.ToLower(c.GetHeader("X-Dev-Admin")) == "true" {
|
||||
c.Set("userRole", "admin")
|
||||
// set a placeholder user
|
||||
c.Set("user", &models.User{Role: "admin"})
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// RoleAuth is a middleware that checks if the user has the required role
|
||||
// Admin always has access. Editor has access to content creation (articles, activities).
|
||||
func RoleAuth(requiredRole string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
userRole, exists := c.Get("userRole")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "User role not found"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Admin always has full access
|
||||
if userRole == "admin" {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// Check if user has the required role
|
||||
if userRole != requiredRole {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Insufficient permissions"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user