您的应用程序已使用不受translate.googleapis.com支持的Google Cloud SDK最终用户凭据进行身份验证。

28

在阅读了类似的问题之后,例如:

我正在使用 GCP 服务账户,但当调用对话流 API 时出现错误:

以及

为什么 Google Cloud API 尝试连接为终端用户?

并尝试了建议的解决方案之后,我仍然收到错误提示:

    Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
  "code" : 403,
  "errors" : [ {
    "domain" : "usageLimits",
    "message" : "Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the translate.googleapis.com. We recommend that most server applications use service accounts instead. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/.",
    "reason" : "rateLimitExceeded"
  } ],
  "message" : "Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the translate.googleapis.com. We recommend that most server applications use service accounts instead. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/.",
  "status" : "PERMISSION_DENIED"

我的pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>seller</groupId>
    <artifactId>home.digest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>home.digest Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://maven.apache.org</url>
    <repositories>
        <repository>
            <id>prime-repo</id>
            <name>Prime Repo</name>
            <url>http://repository.primefaces.org</url>
        </repository>
    </repositories>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.10</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>6.2</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.logging</groupId>
            <artifactId>jboss-logging</artifactId>
            <version>3.0.1.GA</version>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.1-api -->
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.2.Final</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.6.Final</version>
             <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.enterprise/cdi-api -->
        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <version>2.0.SP1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.as</groupId>
            <artifactId>jboss-as-web</artifactId>
            <version>7.1.1.Final</version>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.jboss.spec.javax.ejb/jboss-ejb-api_3.2_spec -->
        <dependency>
            <groupId>org.jboss.spec.javax.ejb</groupId>
            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
            <version>1.0.2.Final</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.cloud/google-cloud-translate -->
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-translate</artifactId>
            <version>1.79.0</version>
        </dependency>
        <dependency>
            <!-- jsoup HTML parser library @ https://jsoup.org/ -->
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.11.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>home.digest</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven 
                defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

我的代码:

com.google.cloud.translate.Translate translate = TranslateOptions.getDefaultInstance().getService();
        String translatexText = "EMPTY";
        try {
            Translation translation = translate.translate("Guten Tag", Translate.TranslateOption.sourceLanguage("de"),
                    Translate.TranslateOption.targetLanguage("bg"),
                    // Use "base" for standard edition, "nmt" for the
                    // premium model.
                    Translate.TranslateOption.model("nmt"));

            translatexText = translation.getTranslatedText();
        } catch (Exception e) {
            Logger.getLogger(TestServlet.class).error(e.getMessage(), e);
        }

        System.out.println(translatexText);
3个回答

39

使用用户凭据设置Cloud SDK时,可能会导致此错误消息。通常使用命令gcloud auth login来完成这个过程。

有几种方法可以解决此问题。每种方法都使用服务帐户。

方法1:

创建一个服务帐户并设置Cloud SDK以使用该服务帐户。

示例命令:

gcloud auth activate-service-account test@development-123456.iam.gserviceaccount.com --key-file=/fullpath/service-account.json

方法2:

设置环境变量GOOGLE_APPLICATION_CREDENTIALS,将其指向您的服务帐号JSON文件。

set GOOGLE_APPLICATION_CREDENTIALS=/fullpath/service-account.json

方法3:

创建Java SDK客户端时指定服务帐号。

此链接显示了指定服务帐号文件的示例:

为服务器端到服务器端生产应用程序设置身份验证


想要按照步骤3操作,但是想要登录GCP SQL实例?该怎么办? - Indrajeet Gour
1
@IndrajeetGour 请创建一个带有详细信息的新问题。 - John Hanley
2
谢谢!就我个人而言,方法1对我没用,而方法2有效。 - Motti
2
@JohnHanley这是否意味着对于某些Google API端点(例如translate.googleapis.comhttps://www.googleapis.com/auth/drive),如果我试图调用它们,就会得到与OP相同的响应,那么没有使用服务帐户通过key.json进行身份验证是不可能的吗? (感谢您在此和其他问题上分享您的知识-非常有帮助!即 https://dev59.com/5lQJ5IYBdhLWcg3wnXN-#53472880 ) - DBCerigo
@DBCerigo - 服务账户是从存储在 key.json 中的私钥派生的。我不使用翻译或驱动API,因此无法发表评论。对于云端,大多数应用程序应该使用服务账户而不是Google账户(gmail、gsuite、cloud identity等)。对于高级用途,用户帐户可以冒充具有正确角色和设置的服务帐户。如果您的应用程序正在运行在Google服务中(Compute Engine、App Engine、Cloud Run、Functions等),那么您可以请求元数据服务器以绕过对 key.json 的需求获取凭据。 - John Hanley
@JohnHanley,由于安全原因,我们不使用key.json。我们现在使用服务账号模拟 - 我们的应用程序确实在GCP服务内运行,但我们需要我们的开发人员能够在本地与API进行交互,因此需要进行模拟。谢谢。 - DBCerigo

7

一般来说,从GCP中运行代码并使用服务帐户是最佳实践。不导出服务帐户密钥也是一个很好的安全实践。所以问题已经得到解答。

在这个额外的回答中,我想分享我的见解,即问题标题中的错误消息发生在何处,发生了什么以及如何设置您的计算机进行一些本地开发而无需导出服务账户密钥(尽管从测试项目中的“一次性”服务账户导出短期服务账户密钥可能更简单且更好的实践,用于测试)。

我想以Sheet API为例说明。表格API至少需要oauth2范围https://www.googleapis.com/auth/spreadsheets.readonly才能从电子表格中读取。

我的Golang示例程序:

package main
 
import (
    "context"
    "fmt"
    "log"
 
    "google.golang.org/api/option"
    "google.golang.org/api/sheets/v4"
)
 
func main() {
    ctx := context.Background()
 
    // using default authentication, whatever the environment provides. See https://cloud.google.com/docs/authentication#environment-service-accounts
    srv, err := sheets.NewService(ctx, option.WithScopes(sheets.SpreadsheetsReadonlyScope))
    if err != nil {
        log.Fatalf("Unable to retrieve Sheets client: %v", err)
    }
 
    // A sample spreadsheet:
    // https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
    spreadsheetId := "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
    readRange := "Class Data!A2:E"
    resp, err := srv.Spreadsheets.Values.Get(spreadsheetId, readRange).Do()
    if err != nil {
        log.Fatalf("Unable to retrieve data from sheet: %v", err)
    }
 
    if len(resp.Values) == 0 {
        fmt.Println("No data found.")
    } else {
        fmt.Println("got some results, ...")
    }
}

我试图从Google Cloud Shell(GCP内置的Web云终端)读取电子表格,带我来到这里的完整错误信息如下:

googleapi: Error 403: Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the sheets.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/., accessNotConfigured

为了通过Google Cloud SDK访问与用户帐户关联的表格,我们需要具有相应OAuth范围的应用程序默认凭据。
$ gcloud auth application-default login --scopes=https://www.googleapis.com/auth/spreadsheets.readonly,openid,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/cloud-platform

我将范围设置为默认值并添加了电子表格范围。当按照基于浏览器的身份验证流程进行操作时,我被要求允许访问。

Google Auth Library to:

View and manage your data across Google Cloud Platform services

View your Google Spreadsheets

在我的电脑上,代码现在可以正常运行。

默认情况下,在未指定--scopes的情况下获取应用程序默认凭据时,你只有权限访问查看和管理您跨 Google Cloud Platform 服务的数据,并且无法与 sheets API 通信。在未指定--scopes的情况下,当尝试与 sheets API 通信时,预期的错误消息为googleapi: Error 403:请求的身份验证范围不足。这是在我的计算机上运行代码时所观察到的。

然而,在 Google Cloud Shell 上运行代码时,我得到了来自问题标题的错误消息,即您的应用程序已使用最终用户凭据进行身份验证...。在 Google Cloud Shell 上运行相应的 gcloud auth application-default login 并指定相应的--scopes也无法改变这种行为。这是因为当代码在 Google Cloud Shell 上运行时,并不会使用应用程序默认凭据。

我编写了一些小型的调试代码,以发现Google API oauth2库如何找到其默认凭据

package main
 
import (
    "context"
    "fmt"
 
    "golang.org/x/oauth2/google"
)
 
func main() {
    ctx := context.Background()
    creds, err := google.FindDefaultCredentials(ctx, "https://www.googleapis.com/auth/spreadsheets.readonly")
    if err != nil {
        panic(fmt.Sprintf("google.FindDefaultCredentials(): %v", err))
    }
    fmt.Printf("creds uses credentials file? %#v\n", creds.JSON != nil)
    t, err := creds.TokenSource.Token()
    if err != nil {
        panic(fmt.Sprintf("Token(): %v", err))
    }
    fmt.Printf("token: %#v\n", t)
}

在我的电脑上,运行了以下命令后:

$ gcloud auth application-default login

我的调试代码输出:

creds uses credentials file? true
token: &oauth2.Token{AccessToken:"...", ..., raw:map[string]interface {}{"access_token":"...", "scope":"https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/accounts.reauth https://www.googleapis.com/auth/cloud-platform openid", "token_type":"Bearer"}}

在我的电脑上,运行后:

$ gcloud auth application-default login --scopes=https://www.googleapis.com/auth/spreadsheets.readonly,openid,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/cloud-platform

我的调试代码输出:

creds uses credentials file? true
token: &oauth2.Token{AccessToken:"...", ..., raw:map[string]interface {}{"access_token":"...", "scope":"https://www.googleapis.com/auth/spreadsheets.readonly https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/accounts.reauth openid https://www.googleapis.com/auth/userinfo.email", "token_type":"Bearer"}}

我们现在已经包含了https://www.googleapis.com/auth/spreadsheets.readonly的范围。

无论我尝试什么,在Google Cloud Shell上运行我的调试代码时,始终会收到以下错误信息:

creds uses credentials file? false
token: &oauth2.Token{AccessToken:"...", ..., raw:map[string]interface {}{"oauth2.google.serviceAccount":"default", "oauth2.google.tokenSource":"compute-metadata"}}

这意味着在Google Cloud Shell上不使用默认应用凭据。这是因为在Google Cloud Shell上,应用程序默认凭据未写入默认位置$HOME/.config/gcloud/application_default_credentials.json,因此google.FindDefaultCredentials()会尝试通过GCP元数据服务器进行身份验证。

1
谢谢。我希望开发人员能够在本地进行开发,但是遇到了这个问题。我正在使用gcloud auth application-default login,并使用sheet api的scopes选项,但是登录失败了。事实证明,您必须至少指定/auth/cloud-platform范围。 - Draxler

3

Firebase CLI

John Hanley的答案很有见地,但是当使用Firebase CLI时也可能会出现此错误。

如果您没有登录任何帐户,请运行:

firebase login

选择所需的Google帐户就可以修复该错误。

当我已经登录并将Firebase添加到现有的G Cloud项目中时,这对我起作用了。 - Kelly Milligan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接