您的应用已使用 Google Cloud SDK 中的最终用户凭据进行身份验证,translate.googleapis.com 不支持这些凭据

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

我正在使用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"

我的.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);

答案 1

此错误消息是由您在设置云 SDK 时使用用户凭证引起的。通常,这是使用命令完成的。gcloud auth login

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

方法 1:

创建服务账号,设置云 SDK 以使用该服务账号。

示例命令:

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

方法 2:

将环境变量设置为指向服务帐户 JSON 文件。GOOGLE_APPLICATION_CREDENTIALS

set GOOGLE_APPLICATION_CREDENTIALS=/fullpath/service-account.json

方法 3:

在创建 Java 开发工具包客户机时指定服务帐户。

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

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


答案 2

通常,最佳做法是从 GCP 运行代码并使用服务帐户。不导出服务帐户密钥也是一种很好的安全做法。所以这个问题已经得到了回答。

在这个额外的答案中,我想分享我的见解,说明问题标题中的错误消息发生在哪里,发生了什么,以及如何设置计算机以在不导出服务帐户密钥的情况下进行一些本地开发(但是,从测试项目中的一次性服务帐户导出短期服务帐户密钥对于测试内容来说可能更简单,更好)。

我想以工作表 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

在我的计算机上,代码现在正在工作。

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

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

我编写了一些小的调试代码来揭示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 上的应用程序默认凭据不会写入默认位置,因此会尝试通过 GCP 元数据服务器进行身份验证。$HOME/.config/gcloud/application_default_credentials.jsongoogle.FindDefaultCredentials()


推荐