【问题标题】:Trouble creating signed URL in App Engine在 App Engine 中创建签名 URL 时遇到问题
【发布时间】:2016-11-09 06:39:17
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

    编写一个对 URL 进行签名的函数很棘手,因为由于加密的性质,当事情不起作用时,很难分辨出哪里出了问题。您可能会发现使用像 gcloud-golang 这样的库更容易,它有一个 SignedURL 方法。

    【讨论】:

    • 谢谢——很好的推荐。该库要求我提供私钥,而 appengine.SignBytes 为我管理密钥。如果我在除 appengine 之外的任何地方执行此操作,我会使用该方法。
    • 这很好。我已提交功能请求:github.com/GoogleCloudPlatform/gcloud-golang/issues/286
    • 更新:现在这是一项功能:)
    【解决方案2】:

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

    这行得通。

    【讨论】:

      【解决方案3】:

      StringToSign 可能需要未解释的换行符。你可以试试这个:

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

      【讨论】:

      • 感谢您的建议。它似乎没有帮助。
      猜你喜欢
      • 2016-08-18
      • 1970-01-01
      • 1970-01-01
      • 2015-08-30
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多