package middleware import ( "crypto/subtle" "net/http" "strings" "github.com/QuantumNous/new-api/setting/system_setting" "github.com/gin-gonic/gin" ) // SyncAuth 同步 API 认证中间件 // 通过 X-Sync-API-Key 请求头验证请求的合法性 func SyncAuth() gin.HandlerFunc { return func(c *gin.Context) { settings := system_setting.GetRegionSyncSettings() // 如果未启用区域同步,拒绝请求 if !settings.Enabled { c.JSON(http.StatusForbidden, gin.H{ "success": false, "message": "region sync is not enabled", }) c.Abort() return } // 检查 X-Sync-API-Key 请求头 apiKey := c.GetHeader("X-Sync-API-Key") if apiKey == "" { c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "missing sync API key", }) c.Abort() return } // 验证 API Key if !validateSyncAPIKey(apiKey, settings.SyncApiKey) { c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "invalid sync API key", }) c.Abort() return } // 验证来源节点(从 X-Sync-Node 获取) node := c.GetHeader("X-Sync-Node") if node == "" { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "missing sync node identifier", }) c.Abort() return } // 将节点信息存储在上下文中 c.Set("sync_node", node) c.Next() } } // validateSyncAPIKey 验证同步 API Key(使用常量时间比较防止 timing attack) func validateSyncAPIKey(requestedKey, configuredKey string) bool { if configuredKey == "" { return false } // 支持 master 配置多个 slave 的 key,以逗号分隔 if strings.Contains(configuredKey, ",") { keys := strings.Split(configuredKey, ",") for _, key := range keys { if subtle.ConstantTimeCompare([]byte(strings.TrimSpace(key)), []byte(requestedKey)) == 1 { return true } } return false } return subtle.ConstantTimeCompare([]byte(strings.TrimSpace(configuredKey)), []byte(requestedKey)) == 1 } // GetSyncNode 从上下文获取同步节点标识 func GetSyncNode(c *gin.Context) string { if node, exists := c.Get("sync_node"); exists { if nodeStr, ok := node.(string); ok { return nodeStr } } return "" }