【问题标题】:How to access a cloud storage bucket from app engine without getting the 403 FORBIDDEN error?如何从应用程序引擎访问云存储桶而不会出现 403 FORBIDDEN 错误?
【发布时间】:2016-08-23 23:11:18
【问题描述】:

我想简单地从应用引擎中提取我的存储桶内容列表并显示它们。

当我在本地开发服务器上运行它时,它运行良好。

但是,当我部署相同的代码应用引擎时,我收到 403 FORBIDDEN 错误。

com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 FORBIDDEN
{
  "code" : 403,
  "errors" : [ {
    "domain" : "global",
    "message" : "Forbidden",
    "reason" : "forbidden"
  } ],
  "message" : "Forbidden"
}
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1056)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
    at com.alpine.servlets.TempServlet.getBucket(TempServlet.java:67)
    at com.alpine.servlets.TempServlet.doGet(TempServlet.java:79)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.google.apphosting.utils.servlet.ParseBlobUploadFilter.doFilter(ParseBlobUploadFilter.java:125)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:37)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.JdbcMySqlConnectionCleanupFilter.doFilter(JdbcMySqlConnectionCleanupFilter.java:60)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:50)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:260)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
    at com.google.apphosting.runtime.jetty.RpcRequestParser.parseAvailable(RpcRequestParser.java:78)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:148)
    at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:468)
    at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:439)
    at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:446)
    at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:256)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:310)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:302)
    at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:443)
    at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:235)
    at java.lang.Thread.run(Thread.java:745)

通过我的research,我确定此错误有很多潜在原因。

  • 拒绝访问
  • 帐户问题
  • AnotherUserOwnsDomain
  • BucketAlreadyExists
  • 禁止跨位置记录
  • 需要域验证
  • 配额不足
  • 无效的AccessKeyId
  • 无效付款人
  • 安全性无效
  • RequestTimeTooSkewed
  • SignatureDoesNotMatch

但是,我无法从堆栈跟踪中确定哪些适用于我的情况。

关于这个主题的Google doc 表明我不应该做任何特别的事情来让它工作:

如果您在 Google App Engine 或 Google 上运行您的应用程序 Compute Engine,环境已经提供了一个服务帐号的 身份验证信息,因此无需进一步设置。为了 Compute Engine,服务帐号范围取决于您的创建方式 实例。请参阅设置服务帐户访问范围 实例。对于 App Engine,使用云平台范围。

应用引擎实例和云存储桶在不同的项目中,但我认为这应该不是问题,因为范围设置为云平台。

doc 将云平台范围描述为:

查看和管理所有 Google Cloud Platform 服务的数据。为了 谷歌云存储,这个和 devstorage.full-control 一样。

我用来建立连接的代码是直接从谷歌的java-doc-samples借来的:

public class StorageFactory {

  private static Storage instance = null;

  public static synchronized Storage getService() throws IOException, GeneralSecurityException {
    if (instance == null) {
      instance = buildService();
    }
    return instance;
  }

  private static Storage buildService() throws IOException, GeneralSecurityException {
    HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
    JsonFactory jsonFactory = new JacksonFactory();
    GoogleCredential credential = GoogleCredential.getApplicationDefault(transport, jsonFactory);

    if (credential.createScopedRequired()) {
      Collection<String> bigqueryScopes = StorageScopes.all();
      credential = credential.createScoped(bigqueryScopes);
    }

    return new Storage.Builder(transport, jsonFactory, credential)
        .setApplicationName("GCS Samples")
        .build();
  }
}

我对如何调试这个问题感到有些困惑。

【问题讨论】:

  • 您对存储桶设置了哪些权限?它们是否包含您的应用引擎服务帐号?
  • 权限目前不包括来自其他项目的应用引擎服务帐号。目前还不清楚如何将特定类型的权限添加到存储桶中。
  • 默认情况下,包括服务帐户在内的项目成员可能具有读取权限。如果您专门设置了权限,则需要包含服务帐户。它和其他任何用户一样都算作用户,因此请添加授予其电子邮件地址读取权限。
  • 效果很好。谢谢。

标签: google-app-engine google-cloud-storage google-api-java-client


【解决方案1】:

使用库specifically built for App Engine。它更容易使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-12
    • 2019-02-03
    • 2020-12-22
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 2019-03-11
    相关资源
    最近更新 更多