在 App Engine 中创建签名 URL 时遇到问题
Trouble creating signed URL in App Engine
我正在尝试创建一个已签名的 URL 以从使用 Go 编写的 App Engine 应用程序下载 Google 云存储中的文件。我正在使用的 App Engine 中有一种巧妙的签名方法,[理论上] 允许我避免在我的应用程序中放置私钥。但是,URLs 似乎不起作用:我总是收到 403 "SignatureDoesNotMatch" 错误。有什么想法吗?
代码如下:
func createDownloadURL(c context.Context, resource string, validUntil time.Time, bucket string) (string, error) {
serviceAccount, err := appengine.ServiceAccount(c)
if err != nil {
return "", err
}
// Build up the string to sign.
validUntilString := strconv.FormatInt(validUntil.Unix(), 10)
toSign := []string{
"GET", // http verb (required)
"", // content MD5 hash (optional)
"", // content type (optional)
validUntilString, // expiration (required)
resource, // resource (required)
}
// Sign it.
_, signedBytes, err := appengine.SignBytes(c, []byte(strings.Join(toSign, "\n")))
if err != nil {
return "", err
}
signedString := base64.StdEncoding.EncodeToString(signedBytes)
// Build and return the URL.
arguments := url.Values{
"GoogleAccessId": {serviceAccount},
"Expires": {validUntilString},
"Signature": {signedString},
}
return fmt.Sprintf("https://storage.googleapis.com/%s/%s?%s", bucket, resource, arguments.Encode()), nil
}
StringToSign 可能需要未解释的换行符。你能试试这个吗:
_, signedBytes, err := appengine.SignBytes(c, []byte(strings.Join(toSign, "\n"))) // escaped newline
已解决。我的代码有 2 个问题。
我在构建 toSign 时忘记包含存储桶名称。修复:
fmt.Sprintf("/%s/%s", bucket, resource), // resource (required)
这返回了 AccessDenied 错误 -- 进度!
第二个错误是使用 XML API storage.googleapis.com 而不是经过身份验证的浏览器端点 storage.cloud.google.com。修复:
return fmt.Sprintf("https://storage.cloud.google.com/%s/%s?%s", bucket, resource, arguments.Encode()), nil
这行得通。
编写一个对 URL 进行签名的函数是很棘手的,因为由于加密的性质,当事情不起作用时很难说出哪里出了问题。您可能会发现使用像 gcloud-golang, which has a SignedURL 方法这样的库更容易。
我正在尝试创建一个已签名的 URL 以从使用 Go 编写的 App Engine 应用程序下载 Google 云存储中的文件。我正在使用的 App Engine 中有一种巧妙的签名方法,[理论上] 允许我避免在我的应用程序中放置私钥。但是,URLs 似乎不起作用:我总是收到 403 "SignatureDoesNotMatch" 错误。有什么想法吗?
代码如下:
func createDownloadURL(c context.Context, resource string, validUntil time.Time, bucket string) (string, error) {
serviceAccount, err := appengine.ServiceAccount(c)
if err != nil {
return "", err
}
// Build up the string to sign.
validUntilString := strconv.FormatInt(validUntil.Unix(), 10)
toSign := []string{
"GET", // http verb (required)
"", // content MD5 hash (optional)
"", // content type (optional)
validUntilString, // expiration (required)
resource, // resource (required)
}
// Sign it.
_, signedBytes, err := appengine.SignBytes(c, []byte(strings.Join(toSign, "\n")))
if err != nil {
return "", err
}
signedString := base64.StdEncoding.EncodeToString(signedBytes)
// Build and return the URL.
arguments := url.Values{
"GoogleAccessId": {serviceAccount},
"Expires": {validUntilString},
"Signature": {signedString},
}
return fmt.Sprintf("https://storage.googleapis.com/%s/%s?%s", bucket, resource, arguments.Encode()), nil
}
StringToSign 可能需要未解释的换行符。你能试试这个吗:
_, signedBytes, err := appengine.SignBytes(c, []byte(strings.Join(toSign, "\n"))) // escaped newline
已解决。我的代码有 2 个问题。
我在构建 toSign 时忘记包含存储桶名称。修复:
fmt.Sprintf("/%s/%s", bucket, resource), // resource (required)
这返回了 AccessDenied 错误 -- 进度!
第二个错误是使用 XML API storage.googleapis.com 而不是经过身份验证的浏览器端点 storage.cloud.google.com。修复:
return fmt.Sprintf("https://storage.cloud.google.com/%s/%s?%s", bucket, resource, arguments.Encode()), nil
这行得通。
编写一个对 URL 进行签名的函数是很棘手的,因为由于加密的性质,当事情不起作用时很难说出哪里出了问题。您可能会发现使用像 gcloud-golang, which has a SignedURL 方法这样的库更容易。