基于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
相关产品推荐
相关产品推荐

