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

Your application has authenticated using end user credentials from the Google Cloud SDK which are not supported by the translate.googleapis.com

看完类似的问题,比如:

并应用建议的解决方案我仍然收到错误:

    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);

此错误消息是由于您在设置 Cloud SDK 时使用了用户凭据引起的。通常这是使用命令 gcloud auth login.

完成的

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

方法一:

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

示例命令:

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

方法二:

设置环境变量 GOOGLE_APPLICATION_CREDENTIALS 以指向您的服务帐户 JSON 文件。

set GOOGLE_APPLICATION_CREDENTIALS=/fullpath/service-account.json

方法三:

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

此 link 显示了指定服务帐户文件的示例:

Setting Up Authentication for Server to Server Production Applications

一般来说,运行从 GCP 获取代码并使用服务帐户是最佳做法。不导出服务帐户密钥也是一种很好的安全做法。所以问题已经回答了。

在这个额外的答案中,我想分享我的见解,问题标题中的错误消息出现在哪里,发生了什么,以及如何设置您的机器以在不导出服务帐户密钥的情况下进行一些本地开发(尽管导出short-lived 来自测试项目中一次性服务帐户的服务帐户密钥可能是测试内容的更简单和更好的做法。

我想以 sheets 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 云 Shell(GCP built-in 网络云终端)读取电子表格,将我带到这里的完整错误消息是:

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

我将范围设置为 default ones 并添加了电子表格范围。在遵循 browser-based 身份验证流程时,系统要求我允许

Google Auth Library to:

View and manage your data across Google Cloud Platform services

View your Google Spreadsheets

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

默认情况下,在未指定 --scopes 的情况下获取应用程序默认凭据时,您将只有 View and manage your data across Google Cloud Platform services 的权限,而不允许与工作表 API 对话。在不指定 --scopes 的情况下,与工作表 API 对话时,预期的错误消息是 googleapi: Error 403: Request had insufficient authentication scopes.。这确实是我在 运行 在我的计算机上运行代码时可以观察到的。

然而,当 运行 在 Google Cloud Shell 上运行代码时,我从问题的标题中得到了错误消息,即 Your application has authenticated using end user credentials ...。此外 运行ning gcloud auth application-default login 与相应的 --scopes 不会改变 Google Cloud Shell 上的这种行为。这是因为当代码是 运行 on Google Cloud Shell 时,不使用应用程序默认凭据。

我写了一些小的调试代码来揭示 Google API oauth2 library is finding its default credentials:

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)
}

在我的电脑上,在 运行ning

之后
$ 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"}}

在我的电脑上,在 运行ning

之后
$ 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 云 Shell 上运行我的调试代码时,我总是得到

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

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

@John Hanley 的回答很有见地,所以我只想添加另一个可能会遇到此错误或类似错误的实例(在我的案例中就是如此):Firebase CLI。我没有登录任何帐户。执行 firebase login 并选择我想要的 Google 帐户足以消除错误