【问题标题】:Facing issue while uploading to Google cloud storage using signed URL使用签名 URL 上传到 Google 云存储时遇到问题
【发布时间】:2016-06-09 15:40:01
【问题描述】:

我正在应用引擎端点中创建signedURL,然后将其提供给客户端。但是当客户端尝试使用签名 URL 上传时,云存储会抛出以下错误

Access denied. Anonymous users does not have storage.objects.create access to bucket

生成签名URL的应用引擎代码如下:

private String getSignedUrl() {
String encodedUrl = null;
String httpVerb = "PUT";
String contentMD5 = "";
String contentType = "image/rgb";

Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 10);
long expiration = calendar.getTimeInMillis() / 1000L;
String canonicalizedExtensionHeaders = "";
String canonicalizedResource =
    "/<bucket_name>/<folder_name>/";

String stringToSign =
    httpVerb + "\n" + contentMD5 + "\n" + contentType + "\n"
        + expiration + "\n" + canonicalizedExtensionHeaders
        + canonicalizedResource;

AppIdentityService service =
    AppIdentityServiceFactory.getAppIdentityService();
String googleAccessId = service.getServiceAccountName();

String baseURL =
    "http://storage.googleapis.com/<bucket_name>/<folder-name>/";
SigningResult signingResult =
    service.signForApp(stringToSign.getBytes());
String encodedSignature = null;
try {
    encodedSignature =
        URLEncoder.encode(
            new String(Base64.encodeBase64(
                signingResult.getSignature(), false),
                "UTF-8"), "UTF-8").toString();
} catch (UnsupportedEncodingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
encodedUrl =
    baseURL + "?GoogleAccessId=" + googleAccessId + "&Expires="
        + expiration + "&Signature=" + encodedSignature;

return encodedUrl;
}

在获得签名的 URL 后,我正在使用 cURL 来测试上传。我使用以下命令上传文件

curl -X PUT -H "Content-Type: multipart/form" -F file=@"<file_path>";type=image/rgb <signed_url>

我在 cURL 中尝试了 POST 和 PUT,结果相同。 我在这里遗漏了什么吗?

【问题讨论】:

  • 我不知道这是否是问题所在,但通常您可能希望为 HTTPS 而不是 HTTP 签署 URL。
  • 即使使用 https 并根据@Andrei 的建议删除文件夹名称后,我也无法从客户端上传。

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


【解决方案1】:

这里从内存中写入,但我认为您需要提供对象名称。另外,您在 baseURL 中包含文件夹名称 - 只应包含存储桶名称。 “文件夹”名称是对象名称的一部分。

【讨论】:

  • 我实际上想生成签名的 URL,以便客户端可以在没有谷歌帐户的情况下上传到 GCS。因此,基本 URL 中没有对象名称。正如您所建议的,我已从代码中的 canonicalizedResourcebaseURL 中删除了文件夹名称。现在我观察到以下错误响应&lt;Error&gt;&lt;Code&gt;MissingSecurityHeader&lt;/Code&gt;&lt;Message&gt;Your request was missing a required header.&lt;/Message&gt;&lt;Details&gt;Authorization&lt;/Details&gt;&lt;/Error&gt;
  • 您能否检查客户端以确保它正在发送 URL 查询参数?这听起来像是在一路剥离 Signature 参数时会发生的事情。另一件值得尝试的事情是给客户端一个已知良好的签名 URL,看看它是否有效。 gsutil 实用程序可以为您生成它们。
  • @SudarshanMurthy:工作流程是这样的:要求用户选择要上传的文件,获取文件名,从后端请求签名 URL,将此 URL 设置为文件上传表单,提交文件上传表单。
  • @BrandonYarbrough 谢谢。客户端 (cURL) 确实从 URL 中剥离了 Signature 和 Expires。在我将整个签名 URL 括在双引号中后,MissingSecurityHeader 错误消失了。但我面临另一个问题。请看下面的评论
  • 我想你在“Content-Type”中忘记了一个连字符
【解决方案2】:

您还必须对 googleAccessIdencodedSignature 进行 URL 编码,因为服务帐户电子邮件中的 @ 符号和 base64 编码字符串可能包含 + 字符,该字符被服务器解码为空格。

【讨论】:

    猜你喜欢
    • 2019-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多