java - 尝试从服务帐户将文件 POST 到 Google Cloud Storage 时收到 403(禁止)

标签 java google-app-engine http rest google-cloud-storage

我想知道是否有人可以告诉我服务帐户将 POST 对象发送到存储桶请求的正确语法和格式?我正在使用 the HttpComponents library 以编程方式尝试它。我设法从我的 GoogleCredential 获取 token ,但每次构造 POST 请求时,我都会得到:

HTTP/1.1 403 Forbidden

<?xml version='1.0' encoding='UTF-8'?><Error><Code>AccessDenied</Code><Message>Access denied.</Message><Details>bucket-name</Details></Error>

谷歌 documentation描述了请求方法,提到使用 html 表单进行发布,但我希望这不是完成工作的唯一方法。我知道 HttpComponents 有一种方法可以使用 UrlEncodedFormEntity 显式创建表单数据,但它不支持多部分数据。这就是我使用 MultipartEntity 类的原因。我的代码如下:

MultipartEntity entity = new MultipartEntity( HttpMultipartMode.BROWSER_COMPATIBLE );
String token = credential.getAccessToken();
entity.addPart("Authorization", new StringBody("OAuth " + token));
String date = formatDate(new Date());
entity.addPart("Date", new StringBody(date));
entity.addPart("Content-Type", new StringBody("multipart/form-data"));
entity.addPart("bucket", new StringBody(bucket));
entity.addPart("key", new StringBody("fileName"));
entity.addPart("success_action_redirect", new StringBody("/storage"));
File uploadFile = new File("pathToFile");
FileBody fileBody = new FileBody(uploadFile, "text/xml");
entity.addPart("file", fileBody);
httppost.setEntity(entity);
System.out.println("Posting URI = "+httppost.toString());
HttpResponse response = client.execute(httppost);
HttpEntity resp_entity = response.getEntity();

正如我所提到的,我能够获得一个实际的 token ,因此我很确定问题在于我如何形成请求,而不是没有经过正确的身份验证。

请记住:

  1. 此操作由服务帐户执行。
  2. 这意味着它确实具有读/写访问权限

感谢您的阅读,感谢您的帮助!

最佳答案

鉴于您使用的 OAuth 访问 token 仅适用于 PUT 和仅适用于 POST 的表单字段,您似乎正在混淆 PUTPOST 方法.

上传对象的最简单方法是使用如下内容:

HttpPut put = new HttpPut("https://storage.googleapis.com/" + BUCKET + "/" + OBJECT);
put.addHeader("Authorization", "Bearer " + credential.getAccessToken());
put.setEntity(new StringEntity("object data"));
client.execute(put);

也可以创建一个签名的 HTML 表单,但比仅使用 PUT 更复杂,用户可以使用该表单通过 POST 上传对象。您的表格需要 signed policy document类似于以下内容:

PolicyDocument = {"expiration": "2010-06-16T11:11:11Z",
 "conditions": [
   ["starts-with", "$key", "" ],
   {"acl": "bucket-owner-read" },
   {"bucket": "travel-maps"},
   {"success_action_redirect": "http://www.example.com/success_notification.html" },
   ["eq", "$Content-Type", "image/jpeg" ],
   ["content-length-range", 0, 1000000]
  ]
}
Policy = Base_64_Encoding_Of(PolicyDocument)
MessageDigest = Sha256_With_RSA(SecretKey, Policy)
Signature = Base64_Encoding_Of(MessageDigest)

这会产生以下 HTML:

<form action="http://travel-maps.storage.googleapis.com" method="post" enctype="multipart/form-data">
<input type="text" name="key" value="">
<input type="hidden" name="bucket" value="travel-maps">
<input type="hidden" name="Content-Type" value="image/jpeg">
<input type="hidden" name="GoogleAccessId" value="<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="74454647404142434c4d444546473410110211181b0411065a13071106021d17111517171b011a005a171b19" rel="noreferrer noopener nofollow">[email protected]</a>">
<input type="hidden" name="acl" value="bucket-owner-read">
<input type="hidden" name="success_action_redirect" value="http://www.example.com/success_notification.html">
<input type="hidden" name="policy" value="ajUJTm9jAHADNmF0aW9uIjogIjIwMTAtMDYtMTZUMTSAMPLEE6MTE6MTFaIiwNCSAMPLEiAgWyJzdGFydSAMPLEAiaHR0cDovL3maWNhSAMPLEIiB9LASAMPLEWN0aW9uX3JlZGlyZW">
<input type="hidden" name="signature" value="BSAMPLEaASAMPLE6SAMPLE+SAMPPLEqSAMPLEPSAMPLE+SAMPLEgSAMPLEzCPlgWREeF7oPGowkeKk7J4WApzkzxERdOQmAdrvshKSzUHg8Jqp1lw9tbiJfE2ExdOOIoJVmGLoDeAGnfzCd4fTsWcLbal9sFpqXsQI8IQi1493mw=">

<input name="file" type="file">
<input type="submit" value="Upload">
</form>

请注意策略和签名字段以及其他隐藏字段,它们与策略文档中指定的条件相匹配。具体来说,bucket == Travel-mapsacl == bucket-owner-read 等。

关于java - 尝试从服务帐户将文件 POST 到 Google Cloud Storage 时收到 403(禁止),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13779266/

相关文章:

java - 在 Debian Linux 上安装 Oracle SQL Developer 时出现问题

java - 使用级数确定 double 的平方根

java - Jfreechart饼图生成

Python Gae Ajax,如何实现通知?

python - 如何调试/分解/学习别人的 Python 代码(基于网络)?

java - Google App Engine Channel API 在 token 过期后重新连接

c - 用于嵌入式系统的轻量级 Web 身份验证

java - 如何在单独的线程中运行java进程

c++ - 适用于 Windows CE/Mobile 的 C++ HTTP Websockets 客户端库

http - HTTP 部分 GET 是一种可靠的机制吗?