如何从应用引擎访问云存储桶而不会收到403 FORBIDDEN错误?

时间:2016-04-28 23:55:21

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

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

当我在本地开发服务器上运行它时,这工作正常。 enter image description here

但是,当我部署相同的代码应用引擎时,我收到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我已经确定这个错误有很多可能的原因。

  • AccessDenied
  • AccountProblem
  • AnotherUserOwnsDomain
  • BucketAlreadyExists
  • CrossLocationLoggingProhibited
  • DomainVerificationRequired
  • InsufficientQuota
  • InvalidAccessKeyId
  • InvalidPayer
  • InvalidSecurity
  • RequestTimeTooSkewed
  • SignatureDoesNotMatch

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

关于这个主题的Google doc表明我不应该做任何特别的事情来实现这个目的:

  

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

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

doc将云平台范围描述为:

  

查看和管理所有Google Cloud Platform服务中的数据。对于   Google Cloud Storage,与devstorage.full-control相同。

我用来获取连接的代码是直接从Google的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();
  }
}

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

1 个答案:

答案 0 :(得分:1)

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