package handlers import ( "crypto/md5" "encoding/hex" "fmt" "net/http" "net/url" "os" "strings" "time" "github.com/gin-gonic/gin" ) type SecureUrlRequest struct { URL string `json:"url"` } // urlEncode 对URL路径进行编码,保持斜杠不变 func urlEncode(s string) string { return strings.ReplaceAll(url.QueryEscape(s), "%2F", "/") } // toHex16 将时间戳转换为16进制小写形式 func toHex16(t int64) string { return fmt.Sprintf("%x", t) } func GenerateSecureURL(c *gin.Context) { var req SecureUrlRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "无效的请求"}) return } // 从环境变量获取防盗链密钥 secretKey := os.Getenv("QINIU_ANTILEECH_KEY") if secretKey == "" { c.JSON(http.StatusInternalServerError, gin.H{"error": "未配置防盗链密钥"}) return } // 设置链接有效期为5分钟 deadline := time.Now().Add(5 * time.Minute).Unix() deadlineHex := toHex16(deadline) // 解析URL parsedURL, err := url.Parse(req.URL) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "无效的URL"}) return } // 获取并编码路径部分 urlPath := parsedURL.Path encodedPath := urlEncode(urlPath) // 构建签名字符串 signStr := secretKey + encodedPath + deadlineHex // 计算MD5签名 hash := md5.New() hash.Write([]byte(signStr)) sign := hex.EncodeToString(hash.Sum(nil)) // 构建查询参数 query := parsedURL.Query() query.Set("sign", sign) query.Set("t", deadlineHex) // 重建URL parsedURL.RawQuery = query.Encode() secureUrl := parsedURL.String() c.JSON(http.StatusOK, gin.H{ "secureUrl": secureUrl, }) }