|
- 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 ""
- }
|