以编程方式为 BigQuery 服务传递服务帐户凭据(JSON 文件)

Posted

技术标签:

【中文标题】以编程方式为 BigQuery 服务传递服务帐户凭据(JSON 文件)【英文标题】:Passing Service Account Credential(JSON File) programmatically for BigQuery Service 【发布时间】:2017-07-21 20:44:54 【问题描述】:

我正在将BigQuery 表中的数据导出到Google Cloud Storage,并且我可以使用应用程序默认凭据成功地做到这一点。我在bash_profile 中设置了环境变量GOOGLE_APPLICATION_CREDENTIALS(此环境变量指向我的服务帐户JSON 文件),这就是我能够检索BigQuery Service(我正在使用Scala(Java API 是用过的))。

val bigquery: BigQuery = BigQueryOptions.getDefaultInstance().getService()

现在,我正在尝试通过以编程方式传递服务帐户JSON 文件而不是使用环境变量(即GOOGLE_APPLICATION_CREDENTIALS)来找到一种方法来检索BigQuery 服务

val inputStream = this.getClass.getResourceAsStream("/GCCredentials.json")
val credentials = GoogleCredentials.fromStream(inputStream)
val bigquery = BigQueryOptions.newBuilder().setCredentials(credentials).build().getService    

但此代码不起作用,我收到以下异常

Exception in thread "main" java.lang.NullPointerException
    at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkNotNull(Preconditions.java:213)
    at com.google.api.client.util.Preconditions.checkNotNull(Preconditions.java:127)

我的代码中缺少什么?

【问题讨论】:

【参考方案1】:

TL;DR - 你错过了FileInputStream

加长版

试试这个:

val fileInputStream = new FileInputStream("/GCCredentials.json")
var credentials = GoogleCredentials.fromStream(fileInputStream)
val bigquery = BigQueryOptions.newBuilder().setCredentials(credentials).build().getService()

使用FileInputStream 读取服务帐户json 文件的内容并将FileInputStream 对象传递给GoogleCredentials 以构建凭据。

或者(仅用于添加信息),如果您知道 json 文件的格式是服务帐户凭据格式,则可以使用 ServiceAccountCredentials 而不是 GoogleCredentials

GoogleCredentials 是读取 OAuth2 凭据以用于任何 Google API 的基类,而 ServiceAccountCredentials 特定于服务帐户。使用其中任何一个都适用于您的情况。

指定要使用的项目

您很可能必须指定要使用的项目 ID(如果您的环境不提供此信息)。如果您没有明确设置,库将尝试猜测要使用的项目 ID。

您可以使用以下环境变量之一指定项目 ID:

GOOGLE_CLOUD_PROJECT GCLOUD_PROJECT

如果未指定这些,它会查看您当前活动的gcloud 配置以检测要使用的项目。

您也可以在代码中明确设置(就像您在 cmets 中描述的那样),如下所示:

val bigquery = BigQueryOptions.newBuilder().setCredentials(credentials).setProjectId("MY_PROJECT_ID").build().getService()

【讨论】:

看起来代码最初可以工作,因为它使用了环境变量GOOGLE_APPLICATION_CREDENTIALS。现在我收到此错误Exception in thread "main" java.lang.IllegalArgumentException: A project ID is required for this service but could not be determined from the builder or the environment. Please set a project ID using the builder....虽然该文件具有项目 ID 看来我必须通过调用BigQueryOptions.newBuilder().setCredentials(credentials).setProjectId(projectID).build().getService() 来指定项目ID。该代码现在有效。但如果项目 ID 已被 API 开箱即用读取会更好 @Raj - 您的服务帐户 json 文件是否包含 project_id 字段? 它确实有字段project_id @Raj - 刚刚意识到它会根据您当前活动的本地 gcloud 配置选择一个默认项目,如果它存在,如果您没有在 BigQueryOptions.Builder 中指定一个。如果没有指定 projectId 并且在您当前的环境中不存在,我会看到您提到的相同错误。或者,可以使用GCLOUD_PROJECT 环境变量来指定项目。

以上是关于以编程方式为 BigQuery 服务传递服务帐户凭据(JSON 文件)的主要内容,如果未能解决你的问题,请参考以下文章

使用 JS 的服务帐户调用 Google bigquery

Google BigQuery:授予服务帐户权限以仅在某些特定数据集中创建作业

如何以编程方式为 WCF 服务创建自签名证书?

agsxmpp 以编程方式创建用户帐户

服务器配置为将传递身份验证和内置帐户一起使用,以访问指定的物理路径。

以编程方式列出已授予访问权限的 Bigquery 数据集,而无需事先知道项目 ID