You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Golang实现Amazon S3浏览器端上传的POST策略创建与签名

动态生成AWS S3 POST上传策略的Golang方案

我懂你现在的痛点——硬编码的策略太不灵活了,每次改参数都要手动修改JSON字符串,很容易出错对吧?下面给你两种实用的动态生成方式,效果就像JS里的模板字面量一样,而且更符合Go的编码习惯:

方法一:用字符串格式化快速实现(类似JS模板字面量)

这种方式最直接,把需要动态替换的部分用%s这类占位符代替,然后用fmt.Sprintf把变量填充进去,和你熟悉的JS模板字面量逻辑差不多:

package main

import (
	"encoding/base64"
	"fmt"
	"time"
)

func main() {
	// 先定义所有需要动态设置的变量
	bucket := "your-bucket-name"
	expiration := time.Now().Add(24 * time.Hour).Format("2006-01-02T15:04:05.000Z") // 24小时后过期
	keyPrefix := "user/user1/"
	acl := "public-read"
	successRedirect := "http://your-domain.com/successful_upload.html"
	contentTypePrefix := "image/"
	uuid := "14365123651274"
	accessKey := "AKIAIOSFODNN7EXAMPLE"
	region := "us-east-1"
	date := time.Now().Format("20060102") // 日期格式要符合AWS要求
	amzDate := time.Now().Format("20060102T150405Z")

	// 用Sprintf动态生成Policy的JSON字符串
	policyStr := fmt.Sprintf(`{
		"expiration": "%s",
		"conditions": [
			{"bucket": "%s"},
			["starts-with", "$key", "%s"],
			{"acl": "%s"},
			{"success_action_redirect": "%s"},
			["starts-with", "$Content-Type", "%s"],
			{"x-amz-meta-uuid": "%s"},
			["starts-with", "$x-amz-meta-tag", ""],
			{"x-amz-credential":"%s/%s/%s/s3/aws4_request"},
			{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
			{"x-amz-date": "%s"}
		]
	}`, expiration, bucket, keyPrefix, acl, successRedirect, contentTypePrefix, uuid, accessKey, date, region, amzDate)

	// 编码为Base64
	base64Policy := base64.StdEncoding.EncodeToString([]byte(policyStr))
	fmt.Println(base64Policy)
}

方法二:用结构体序列化(更安全、易维护)

如果你的策略逻辑比较复杂,或者担心手动拼接JSON会出现语法错误,推荐用结构体+JSON序列化的方式。这种方式让代码更清晰,还能自动处理JSON的格式问题:

package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"time"
)

// 定义Policy结构体,对应S3策略的JSON结构
type Policy struct {
	Expiration string        `json:"expiration"`
	Conditions []interface{} `json:"conditions"`
}

func main() {
	// 动态变量和上面一致
	bucket := "your-bucket-name"
	expiration := time.Now().Add(24 * time.Hour).Format("2006-01-02T15:04:05.000Z")
	keyPrefix := "user/user1/"
	acl := "public-read"
	successRedirect := "http://your-domain.com/successful_upload.html"
	contentTypePrefix := "image/"
	uuid := "14365123651274"
	accessKey := "AKIAIOSFODNN7EXAMPLE"
	region := "us-east-1"
	date := time.Now().Format("20060102")
	amzDate := time.Now().Format("20060102T150405Z")

	// 构建Conditions数组,里面可以混合map和slice(对应策略里的两种条件格式)
	conditions := []interface{}{
		map[string]string{"bucket": bucket},
		[]interface{}{"starts-with", "$key", keyPrefix},
		map[string]string{"acl": acl},
		map[string]string{"success_action_redirect": successRedirect},
		[]interface{}{"starts-with", "$Content-Type", contentTypePrefix},
		map[string]string{"x-amz-meta-uuid": uuid},
		[]interface{}{"starts-with", "$x-amz-meta-tag", ""},
		map[string]string{"x-amz-credential": fmt.Sprintf("%s/%s/%s/s3/aws4_request", accessKey, date, region)},
		map[string]string{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
		map[string]string{"x-amz-date": amzDate},
	}

	// 创建Policy实例并填充数据
	policy := Policy{
		Expiration: expiration,
		Conditions: conditions,
	}

	// 序列化为JSON字节数组
	policyBytes, err := json.Marshal(policy)
	if err != nil {
		fmt.Println("生成Policy出错:", err)
		return
	}

	// 编码为Base64
	base64Policy := base64.StdEncoding.EncodeToString(policyBytes)
	fmt.Println(base64Policy)
}

补充:生成AWS签名的步骤

你现在只完成了Policy的Base64编码,接下来还需要生成签名才能让S3接受请求。这里给你一个简单的签名生成示例:

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
)

// 生成AWS4签名所需的Signing Key
func generateSigningKey(secretKey, date, region, service string) []byte {
	key := []byte("AWS4" + secretKey)
	key = hmacSHA256(key, []byte(date))
	key = hmacSHA256(key, []byte(region))
	key = hmacSHA256(key, []byte(service))
	key = hmacSHA256(key, []byte("aws4_request"))
	return key
}

// 计算HMAC-SHA256
func hmacSHA256(key, data []byte) []byte {
	h := hmac.New(sha256.New, key)
	h.Write(data)
	return h.Sum(nil)
}

// 在main函数里调用:
// signingKey := generateSigningKey("your-aws-secret-key", date, region, "s3")
// signature := hmacSHA256(signingKey, []byte(base64Policy))
// hexSignature := hex.EncodeToString(signature)
// fmt.Println("最终签名:", hexSignature)

这样你就能把动态生成的Policy和签名一起返回给AngularJS客户端,用于浏览器端的S3上传了。

内容的提问来源于stack exchange,提问作者Prashanth Hegde

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:22:19