package handlers import ( "net/http" "smoop-api/internal/crypto" "strings" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" ) func Auth(jwtMgr *crypto.JWTManager) gin.HandlerFunc { return func(c *gin.Context) { h := c.GetHeader("Authorization") if !strings.HasPrefix(h, "Bearer ") { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing bearer token"}) return } tok := strings.TrimPrefix(h, "Bearer ") token, err := jwtMgr.Parse(tok) if err != nil || !token.Valid { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"}) return } claims, _ := token.Claims.(jwt.MapClaims) c.Set("claims", claims) c.Next() } } func RequireRole(role string) gin.HandlerFunc { return func(c *gin.Context) { claims := MustClaims(c) if ClaimRole(claims) != role { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "forbidden"}) return } c.Next() } } // helpers used by handlers func MustClaims(c *gin.Context) map[string]interface{} { val, ok := c.Get("claims") if !ok { return jwt.MapClaims{} } switch t := val.(type) { case jwt.MapClaims: return t case map[string]interface{}: return jwt.MapClaims(t) default: return jwt.MapClaims{} } } func ClaimUserID(claims map[string]interface{}) uint { if claims == nil { return 0 } if v, ok := claims["sub"]; ok { switch n := v.(type) { case float64: return uint(n) case int: return uint(n) case int64: return uint(n) } } return 0 } func ClaimRole(claims map[string]interface{}) string { if r, ok := claims["role"].(string); ok { return r } return "" }