GCloud生成PUT预签名URL遇SignatureDoesNotMatch错误求助
Google Cloud 预签名URL签名不匹配问题排查与解决
问题描述
我用Go语言编写了生成GCS预签名PUT URL的代码,用于上传文档:
func GetSignedURL(bucketName string, objectName string) string { ctx := context.Background() // Get a connection to gcloud client, err := storage.NewClient(ctx, option.WithCredentialsFile(config.GetSettings().GoogleCloudKey)) if err != nil { msg := err.Error() + " @ " + whereami.WhereAmI() + " on " + helpers.GetTimeInTimezone() panic(msg) } defer client.Close() opts := &storage.SignedURLOptions{ Scheme: storage.SigningSchemeV4, Method: "PUT", PrivateKey: []byte(getPrivateKey()), //<- a Google service account private key, obtainable from the Google Developers Console Expires: time.Now().Add(15 * time.Minute), Insecure: false, } //Use connection to get url url, err := client.Bucket(bucketName).SignedURL(objectName, opts) if err != nil { msg := err.Error() + " @ " + whereami.WhereAmI() + " on " + helpers.GetTimeInTimezone() panic(msg) } return url }
生成的URL格式如下:
https://storage.googleapis.com/yyy-vv-upload-xxx/aa41dcaed3a24f65b8d5a9ac94b4c0a6?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=xxx-assets-gcs-yyy-devops%40yyy-devops.iam.gserviceaccount.com%2F20226667%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20221227T183246Z&X-Goog-Expires=899&X-Goog-Signature=260b2e695999ccdea5d5d5e46f0f83d204609dbfc0efcdf1fa8381b9ec748eacad36b525e695c6fc2fb02277a56e3c10674a75de2ba83c668c2052a89192345ddbdd0fe841ea28dc7df01648f2ca420b43d6fa162540e1c34865847d34c832ded157f2ec58bd8d57c47eef32d632ff02dc1927dc94f7509795e78c357dc556e2c96ea8e86dfb5015c796627f327caf04f45560bad4d5cdb714c5bc97d442cbc87639f44b2a102ce9d9a3fc83e81bcaf9fde38ce56efd02decd3fe8a1cf5fc823e46c85b39d7ada41618993e80b5c2e61a0380d403d0d6763310350ab1cf22d539c80fdaafc2320cbdeb3f1e7c21b4c40e3dc8889b348f67573852d5e7986167e&X-Goog-SignedHeaders=host
但在浏览器中访问该URL时,返回签名不匹配错误:
<Error> <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message> <StringToSign>GOOG4-RSA-SHA256 20221227T183246Z 20221227/auto/storage/goog4_request 78f5677e7572233dc56657f7b055601eee26e7913bb6426194c888367c521990</StringToSign> <CanonicalRequest>GET /yyy-vv-upload-xxx/aa41dcaed3a24f65b8d5a9ac94b4c0a6 X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=xxx-assets-gcs-yyy-devops%40yyy-devops.iam.gserviceaccount.com%2F20221227%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20221227T183246Z&X-Goog-Expires=899&X-Goog-SignedHeaders=host host:storage.googleapis.com host UNSIGNED-PAYLOAD</CanonicalRequest> </Error>
解决建议
- 请求方法不匹配:从错误返回的
CanonicalRequest可以看到,浏览器发起的是GET请求,但生成URL时指定的是PUT方法。预签名URL的签名和请求方法强绑定,必须用对应方法访问。不能直接在浏览器地址栏测试PUT URL,需用curl、Postman等工具发起PUT请求,示例:curl -X PUT -d "test content" "你的预签名URL" - 私钥完整性验证:确认
getPrivateKey()返回的服务账号私钥完整,包含-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----首尾行,无多余空格或换行。 - 修复Credential无效日期:生成的URL中
X-Goog-Credential里的日期是20226667,属于无效格式。检查服务器系统时间是否与UTC同步,误差不要超过5分钟,确保time.Now()获取的是正确时间,建议改用time.Now().UTC()生成过期时间。 - 同步签名头与请求头:如果实际请求带有额外头(如
Content-Type),需在生成URL时将其添加到SignedHeaders列表中,否则会导致签名验证失败。 - 简化代码逻辑:生成预签名URL无需初始化完整的
storage.Client,可直接使用storage.SignedURL函数,避免客户端配置带来的潜在问题,简化示例:import ( "time" "cloud.google.com/go/storage" ) func GetSignedURL(bucketName string, objectName string) (string, error) { opts := &storage.SignedURLOptions{ Scheme: storage.SigningSchemeV4, Method: "PUT", PrivateKey: []byte(getPrivateKey()), Expires: time.Now().UTC().Add(15 * time.Minute), // 若需指定Content-Type,取消注释下面一行 // ContentType: "application/octet-stream", } return storage.SignedURL(bucketName, objectName, opts) }
内容的提问来源于stack exchange,提问作者pigfox
相关产品推荐
相关产品推荐

