RealmDramaAPI 开发者文档
使用指南火山兼容APIOpenAI 兼容API在线调试帮助支持

素材库认证与签名

Bearer API Key 与火山 ARK HMAC-SHA256 签名规则

素材库 Action API 支持 Bearer API Key 和 AK/SK HMAC-SHA256。两种方式任选其一,不要在同一个请求中混用。火山兼容视频生成任务接口使用 Authorization: Bearer,不使用素材 Action 的 AK/SK 签名。

认证方式一 : Bearer API Key

兼容网关可使用 Bearer API Key:

Authorization: Bearer sk-your-api-key
Content-Type: application/json

API Key 所属用户必须启用并拥有素材访问权限。Token 过期、停用或 IP 白名单不匹配时,请求会被拒绝。

认证方式二 :AK/SK HMAC-SHA256

火山 SDK 和界云素材 SDK 使用 Access Key 与 Secret Key 签名。固定参数如下:

参数
Regioncn-beijing
Serviceark
AlgorithmHMAC-SHA256
Version2024-01-01

必需请求头:

Content-Type: application/json
Host: jieyun.cc
X-Date: 20260721T040000Z
X-Content-Sha256: <lowercase sha256 hex of request body>
Authorization: HMAC-SHA256 Credential=<AK>/<date>/cn-beijing/ark/request, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature=<hex>

Host 必须与实际 Endpoint 一致,当前使用 jieyun.cc

签名步骤

  1. 对原始 JSON 请求体计算 SHA-256,将小写十六进制结果写入 X-Content-Sha256
  2. 构造 Canonical Request:HTTP 方法、Canonical URI、Canonical Query String、Canonical Headers、Signed Headers 和请求体哈希。
  3. 使用 HMAC-SHA256X-Date、凭证范围和 Canonical Request 哈希构造 String to Sign。
  4. 按日期、区域、服务名和 request 的顺序派生签名密钥,再计算最终 Signature。

请求时间与服务端时间偏差不能超过 5 分钟。不支持 X-Security-Token 临时安全凭证。

Go 签名示例

下面的示例仅使用 Go 标准库,请通过环境变量传入 AK/SK。请求体必须先序列化为字节,再使用同一组字节计算哈希并发送;计算签名后不要重新格式化或修改 JSON。

package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"sort"
	"strings"
	"time"
)

const (
	region  = "cn-beijing"
	service = "ark"
	action  = "CreateAssetGroup"
	version = "2024-01-01"
)

func sha256Hex(value []byte) string {
	sum := sha256.Sum256(value)
	return hex.EncodeToString(sum[:])
}

func hmacSHA256(key []byte, value string) []byte {
	mac := hmac.New(sha256.New, key)
	mac.Write([]byte(value))
	return mac.Sum(nil)
}

func encode(value string) string {
	return strings.ReplaceAll(url.QueryEscape(value), "+", "%20")
}

func main() {
	accessKey := os.Getenv("ARK_ACCESS_KEY")
	secretKey := os.Getenv("ARK_SECRET_KEY")
	if accessKey == "" || secretKey == "" {
		panic("请设置 ARK_ACCESS_KEY 和 ARK_SECRET_KEY")
	}

	// 先确认请求体。后续计算哈希和发送请求必须复用 body。
	body, err := json.Marshal(struct {
		Name        string `json:"Name"`
		Description string `json:"Description"`
		GroupType   string `json:"GroupType"`
		ProjectName string `json:"ProjectName"`
	}{
		Name:        "产品素材",
		Description: "产品图片和视频素材",
		GroupType:   "AIGC",
		ProjectName: "default",
	})
	if err != nil {
		panic(err)
	}

	endpoint, err := url.Parse("https://jieyun.cc/")
	if err != nil {
		panic(err)
	}
	query := map[string]string{
		"Action":  action,
		"Version": version,
	}
	keys := make([]string, 0, len(query))
	for key := range query {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	parts := make([]string, 0, len(keys))
	for _, key := range keys {
		parts = append(parts, encode(key)+"="+encode(query[key]))
	}
	canonicalQuery := strings.Join(parts, "&")
	endpoint.RawQuery = canonicalQuery

	xDate := time.Now().UTC().Format("20060102T150405Z")
	shortDate := xDate[:8]
	payloadHash := sha256Hex(body)
	signedHeaders := "content-type;host;x-content-sha256;x-date"
	canonicalHeaders := strings.Join([]string{
		"content-type:application/json",
		"host:" + endpoint.Host,
		"x-content-sha256:" + payloadHash,
		"x-date:" + xDate,
		"",
	}, "\n")
	canonicalRequest := strings.Join([]string{
		"POST",
		endpoint.EscapedPath(),
		canonicalQuery,
		canonicalHeaders,
		signedHeaders,
		payloadHash,
	}, "\n")

	credentialScope := fmt.Sprintf(
		"%s/%s/%s/request",
		shortDate,
		region,
		service,
	)
	stringToSign := strings.Join([]string{
		"HMAC-SHA256",
		xDate,
		credentialScope,
		sha256Hex([]byte(canonicalRequest)),
	}, "\n")
	dateKey := hmacSHA256([]byte(secretKey), shortDate)
	regionKey := hmacSHA256(dateKey, region)
	serviceKey := hmacSHA256(regionKey, service)
	signingKey := hmacSHA256(serviceKey, "request")
	signature := hex.EncodeToString(hmacSHA256(signingKey, stringToSign))
	authorization := fmt.Sprintf(
		"HMAC-SHA256 Credential=%s/%s, SignedHeaders=%s, Signature=%s",
		accessKey,
		credentialScope,
		signedHeaders,
		signature,
	)

	request, err := http.NewRequest(
		http.MethodPost,
		endpoint.String(),
		bytes.NewReader(body),
	)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", authorization)
	request.Header.Set("Content-Type", "application/json")
	request.Header.Set("X-Date", xDate)
	request.Header.Set("X-Content-Sha256", payloadHash)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	responseBody, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%s\n%s\n", response.Status, responseBody)
}

运行示例:

ARK_ACCESS_KEY="ak-your-access-key" \
ARK_SECRET_KEY="your-secret-key" \
go run main.go

SDK 配置

完整的 SDK 配置与调用示例请参阅素材库 API 概览

config := volcengine.NewConfig().
    WithCredentials(credentials.NewStaticCredentials(accessKey, secretKey, "")).
    WithRegion("cn-beijing").
    WithEndpoint("jieyun.cc")

client := ark.New(session.Must(session.NewSession(config)))

SDK 会自动添加 Action、Version、请求体哈希和签名请求头。Endpoint 使用 jieyun.cc