package middleware import ( "net/http" "strings" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" "github.com/wangjia/jiu/backend/config" ) type Claims struct { UserID uint64 `json:"user_id"` ShopID uint64 `json:"shop_id"` Role string `json:"role"` jwt.RegisteredClaims } const ( CtxUserID = "user_id" CtxShopID = "shop_id" CtxRole = "role" ) func JWT() gin.HandlerFunc { return func(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing token"}) return } tokenStr := strings.TrimPrefix(authHeader, "Bearer ") claims := &Claims{} token, err := jwt.ParseWithClaims(tokenStr, claims, func(t *jwt.Token) (interface{}, error) { return []byte(config.C.JWT.Secret), nil }) if err != nil || !token.Valid { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"}) return } c.Set(CtxUserID, claims.UserID) c.Set(CtxShopID, claims.ShopID) c.Set(CtxRole, claims.Role) c.Next() } } // AdminOnly 仅管理员可访问 func AdminOnly() gin.HandlerFunc { return func(c *gin.Context) { role, _ := c.Get(CtxRole) if role != "admin" && role != "superadmin" { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "admin only"}) return } c.Next() } } // ReadOnly 只读用户禁止写操作 func ReadOnly() gin.HandlerFunc { return func(c *gin.Context) { role, _ := c.Get(CtxRole) if role == "readonly" && c.Request.Method != "GET" { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "readonly user"}) return } c.Next() } } // GetShopID 从 context 中安全获取 shop_id func GetShopID(c *gin.Context) uint64 { v, _ := c.Get(CtxShopID) id, _ := v.(uint64) return id } // GetUserID 从 context 中安全获取 user_id func GetUserID(c *gin.Context) uint64 { v, _ := c.Get(CtxUserID) id, _ := v.(uint64) return id } // SuperAdminOnly 仅超级管理员可访问 func SuperAdminOnly() gin.HandlerFunc { return func(c *gin.Context) { role, _ := c.Get(CtxRole) if role != "superadmin" { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "superadmin only"}) return } c.Next() } }