无法在App Engine中创建签名URL

时间:2016-07-07 03:20:25

标签: google-app-engine go google-cloud-storage

我尝试使用Go编写的App Engine应用程序创建一个签名URL,以便在Google云端存储中下载文件。我正在使用的App Engine中有一个漂亮的签名方法,[理论上]允许我避免在我的应用程序中放置私钥。但是,网址似乎不起作用:我总是得到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
}

3 个答案:

答案 0 :(得分:1)

解决。我的代码有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

这很有效。

答案 1 :(得分:0)

StringToSign可能需要未解释的换行符。你可以尝试一下:

_, signedBytes, err := appengine.SignBytes(c, []byte(strings.Join(toSign, "\\n"))) // escaped newline

答案 2 :(得分:0)

编写一个签署URL的函数很棘手,因为由于加密的性质,当事情不起作用时很难说出错误。您可能会发现使用gcloud-golang这样的库更容易,它有SignedURL方法。