3

我正在尝试使用服务帐户方法访问 Google BigQuery。我的代码如下:

private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();

private static final JsonFactory JSON_FACTORY = new JacksonFactory();

GoogleCredential credentials = new GoogleCredential.Builder()
            .setTransport(HTTP_TRANSPORT)
            .setJsonFactory(JSON_FACTORY)
            .setServiceAccountId("XXXXX@developer.gserviceaccount.com")
            .setServiceAccountScopes(BigqueryScopes.BIGQUERY)
            .setServiceAccountPrivateKeyFromP12File(
                    new File("PATH-TO-privatekey.p12"))
            .build();
    Bigquery bigquery = Bigquery.builder(HTTP_TRANSPORT, JSON_FACTORY).setHttpRequestInitializer(credentials)
            .build();
    com.google.api.services.bigquery.Bigquery.Datasets.List datasetRequest = bigquery.datasets().list(
            "PROJECT_ID");

    DatasetList datasetList = datasetRequest.execute();
    if (datasetList.getDatasets() != null) {
        java.util.List<Datasets> datasets = datasetList.getDatasets();
        System.out.println("Available datasets\n----------------");
        for (Datasets dataset : datasets) {
            System.out.format("%s\n", dataset.getDatasetReference().getDatasetId());
        }
    }

但它会引发以下异常:

Exception in thread "main"  com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
  "code" : 401,
  "errors" : [ {
    "domain" : "global",
    "location" : "Authorization",
    "locationType" : "header",
    "message" : "Authorization required",
    "reason" : "required"
  } ],
  "message" : "Authorization required"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:159)
at com.google.api.client.googleapis.json.GoogleJsonResponseException.execute(GoogleJsonResponseException.java:187)
at com.google.api.client.googleapis.services.GoogleClient.executeUnparsed(GoogleClient.java:115)
at com.google.api.client.http.json.JsonHttpRequest.executeUnparsed(JsonHttpRequest.java:112)
at com.google.api.services.bigquery.Bigquery$Datasets$List.execute(Bigquery.java:979)

异常在这一行被触发:

  DatasetList datasetList = datasetRequest.execute();

我从 Google API 控制台的第二行获取帐户 ID,如下所示:

    Client ID:  XXXXX.apps.googleusercontent.com
    Email address:  XXXXX@developer.gserviceaccount.com

我错过了什么?

4

4 回答 4

5

尤里卡!Eric 和 Michael 的代码都运行良好。

通过错误地设置客户端计算机上的时间,可以重现问题中发布的错误。幸运的是,可以通过正确设置客户端机器上的时间来解决

注意:对于它的价值,我使用“Internet 时间设置”对话框中的“立即更新”按钮同步了 Windows 7 机器上的时间。我认为这应该是非常防白痴的......但我想我击败了系统。它更正了秒数,但机器关闭了整整一分钟。之后 BigQuery 调用失败。我手动更改时间后它成功了。

于 2012-05-10T22:56:56.860 回答
2

我们在 Java 库中的错误处理代码需要改进一下!

用于请求 OAuth 访问令牌的签名 JWT 似乎失败了。您可以通过启用上面提到的@MichaelManoochehri 的日志来看到这一点。

我认为只有几件事可能导致此失败:

  1. 无效的签名(使用错误的密钥)
  2. 服务帐户的电子邮件地址无效(我认为已排除)
  3. 用于生成签名 blob 的日期/时间戳无效(发布日期和到期日期)
  4. 范围无效(我认为已排除)

您应该使用正确的时区检查您的服务器上的日期/时间是否正确设置——同步到 NTP。您可以使用 time.gov 查看美国官方原子钟时间。

于 2012-05-10T22:58:28.940 回答
1

编辑:我在下面给出的答案与使用 Google App Engine 服务帐户有关 - 留在这里以供参考。

仔细检查您是否已将服务帐户地址作为所有者添加到项目的团队页面。

我建议使用 AppIdentityCredential 类来处理服务帐户身份验证。这是一个演示这一点的小片段,我将在 BigQuery API 开发人员页面上添加有关此的其他文档。

此外,请确保您使用的是最新版本的 Google Java API 客户端(截至今天,此处为“v2-rev5-1.5.0-beta”版本

import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.http.json.JsonHttpRequest;
import com.google.api.client.http.json.JsonHttpRequestInitializer;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.bigquery.Bigquery;
import com.google.api.services.bigquery.BigqueryRequest;

@SuppressWarnings("serial")
public class Bigquery_service_accounts_demoServlet<TRANSPORT> extends HttpServlet {

// ENTER YOUR PROJECT ID HERE
private static final String PROJECT_ID = "";

private static final HttpTransport TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
private static final String BIGQUERY_SCOPE = "https://www.googleapis.com/auth/bigquery";


AppIdentityCredential credential = new AppIdentityCredential(BIGQUERY_SCOPE);
Bigquery bigquery = Bigquery.builder(TRANSPORT,JSON_FACTORY)

 .setHttpRequestInitializer(credential)
 .setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
   public void initialize(JsonHttpRequest request) {
     BigqueryRequest bigqueryRequest = (BigqueryRequest) request;
     bigqueryRequest.setPrettyPrint(true);
   }
 }).build();    

public void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws IOException {
  resp.setContentType("text/plain");
  resp.getWriter().println(bigquery.datasets()
    .list(PROJECT_ID)
    .execute().toString());
 }
}
于 2012-05-09T22:16:35.107 回答
-1

这是一个完整的片段供参考:

import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.bigquery.Bigquery;
import com.google.api.services.bigquery.Bigquery.Datasets;
import com.google.api.services.bigquery.model.DatasetList;

import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;


public class BigQueryJavaServiceAccount {

  private static final String SCOPE = "https://www.googleapis.com/auth/bigquery";
  private static final HttpTransport TRANSPORT = new NetHttpTransport();
  private static final JsonFactory JSON_FACTORY = new JacksonFactory();

  public static void main(String[] args) throws IOException, GeneralSecurityException {
    GoogleCredential credential = new GoogleCredential.Builder().setTransport(TRANSPORT)
        .setJsonFactory(JSON_FACTORY)
        .setServiceAccountId("XXXXXXX@developer.gserviceaccount.com")
        .setServiceAccountScopes(SCOPE)
        .setServiceAccountPrivateKeyFromP12File(new File("my_file.p12"))
        .build();

    Bigquery bigquery = Bigquery.builder(TRANSPORT, JSON_FACTORY)
        .setApplicationName("Google-BigQuery-App/1.0")
        .setHttpRequestInitializer(credential).build();

    Datasets.List datasetRequest = bigquery.datasets().list("publicdata");
    DatasetList datasetList = datasetRequest.execute();
    System.out.format("%s\n", datasetList.toPrettyString()); 
}
于 2012-05-10T01:05:20.050 回答