使用Oauth连接到Google Compute Engine

5
我正在尝试使用Java连接Google Compute Engine,但遇到了一个对我来说意义不大的异常。
我正在遵循的示例中给出了以下内容:
/** Authorizes the installed application to access user's protected data. */
private static Credential authorize() throws Exception {
  // load client secrets
  GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
      new InputStreamReader(CalendarSample.class.getResourceAsStream("/client_secrets.json")));
  // set up authorization code flow
  GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
      httpTransport, JSON_FACTORY, clientSecrets,
      Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(dataStoreFactory)
      .build();
  // authorize
  return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
} 

为了获取包含凭据的json文件,我需要前往cloud.google.com,并在控制台中找到我的应用程序,点击“Credentials”。接着我点击“Create new ClientId”,选择“Service Account”和“JSON Key”。
这将下载一个“_________.json”文件。
在“public static void main(String ... args) throws Exception {”代码块中,我有以下代码来读取凭据文件:
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
                new FileReader("________9f.json"));

执行System.out.println(clientSecrets);将打印包含private_key_idclient_emailclient_idtype密钥的整个json文件。

接下来,如果我继续使用示例代码:

// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
        httpTransport, JSON_FACTORY, clientSecrets,
                    Collections.singleton(ComputeScopes.COMPUTE)).setDataStoreFactory(dataStoreFactory).build();

// authorize
new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");

这给了我以下的堆栈跟踪:

主线程中的异常“main”java.lang.IllegalArgumentException at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument(Preconditions.java:76) at com.google.api.client.util.Preconditions.checkArgument(Preconditions.java:37) at com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.getDetails(GoogleClientSecrets.java:82) at com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow$Builder.(GoogleAuthorizationCodeFlow.java:195) at com.mycee.TestGoogle.main(TestGoogle.java:52) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

缺失的变量(目前都是静态变量)如下:
JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
FileDataStoreFactory dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".store/compute_engine_sample");

我正在尝试通过Java管理我的Google Compute Engine实例,关于Oath身份验证,您有什么想法我做错了什么吗?
更新:
如请求的那样,pom.xml文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.jvaas</groupId>
    <artifactId>jvaas-cloud</artifactId>
    <packaging>war</packaging>
    <version>1.0.0</version>
    <name>jVaaS Cloud</name>
    <properties>
        <jclouds.version>1.9.0</jclouds.version>
        <project.http.version>1.19.0</project.http.version>
        <project.oauth.version>1.19.0</project.oauth.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.google.http-client</groupId>
            <artifactId>google-http-client-jackson2</artifactId>
            <version>${project.http.version}</version>
        </dependency>
        <dependency>
            <groupId>com.google.oauth-client</groupId>
            <artifactId>google-oauth-client-jetty</artifactId>
            <version>${project.oauth.version}</version>
        </dependency>
        <dependency>
            <groupId>com.google.apis</groupId>
            <artifactId>google-api-services-compute</artifactId>
            <version>v1-rev27-1.19.0</version>
        </dependency>
    </dependencies>
</project>

在默认包中的TestGoogle.java (kots.json位于src/main/resources):

import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.compute.Compute;
import com.google.api.services.compute.ComputeScopes;
import com.google.api.services.compute.model.Instance;
import com.google.api.services.compute.model.InstanceList;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

public class TestGoogle {

    private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".store/compute_engine_sample");
    private static FileDataStoreFactory dataStoreFactory;
    private static HttpTransport httpTransport;
    private static final String zoneName = "us-central1-a";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final List<String> SCOPES = Arrays.asList(ComputeScopes.COMPUTE_READONLY);

    public static void main(String... args) throws Exception {

        httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);

        InputStream in = TestGoogle.class.getResourceAsStream("/kots.json");

        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
        GoogleAuthorizationCodeFlow flow = // <- fails here
                new GoogleAuthorizationCodeFlow.Builder(
                        httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
                        .setDataStoreFactory(dataStoreFactory)
                        .setAccessType("online").setApprovalPrompt("auto")
                        .build();

        new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");

    }
}

完整的堆栈跟踪:

Exception in thread "main" java.lang.IllegalArgumentException
    at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument(Preconditions.java:76)
    at com.google.api.client.util.Preconditions.checkArgument(Preconditions.java:37)
    at com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.getDetails(GoogleClientSecrets.java:82)
    at com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow$Builder.<init>(GoogleAuthorizationCodeFlow.java:195)
    at TestGoogle.main(TestGoogle.java:38)

对相关的类文件进行反编译,以下是与代码片段相关的内容:

GoogleAuthorizationCodeFlow.java: 195

public Builder(HttpTransport transport, JsonFactory jsonFactory, GoogleClientSecrets clientSecrets, Collection<String> scopes) {
    super(BearerToken.authorizationHeaderAccessMethod(), transport, jsonFactory, new GenericUrl("https://accounts.google.com/o/oauth2/token"), new ClientParametersAuthentication(clientSecrets.getDetails().getClientId(), clientSecrets.getDetails().getClientSecret()), clientSecrets.getDetails().getClientId(), "https://accounts.google.com/o/oauth2/auth");
    this.setScopes(scopes);
}

GoogleClientSecrets.java: 82

public GoogleClientSecrets.Details getDetails() {
    Preconditions.checkArgument(this.web == null != (this.installed == null));
    return this.web == null?this.installed:this.web;
}

Preconditions.java: 37

public static void checkArgument(boolean expression) {
    com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument(expression);
}

前置条件.java:76

(这是一个代码行号)
public static void checkArgument(boolean expression) {
    if(!expression) {
        throw new IllegalArgumentException();
    }
}

将所有敏感数据屏蔽的kots.json:

{
  "private_key_id": "________________________________________",
  "private_key": "-----BEGIN PRIVATE KEY-----\n__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________\n-----END PRIVATE KEY-----\n",
  "client_email": "_____________________________________________@developer.gserviceaccount.com",
  "client_id": "_____________________________________________.apps.googleusercontent.com",
  "type": "service_account"
}

当我在cloud.google.com上点击此按钮时,kots.json文件被生成。

enter image description here

更新:看起来我的json文件有误,这个格式修复了它(从与@We are Borg的对话中复制):

{"installed": {
    "client_id": "yourid",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://accounts.google.com/o/oauth2/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_email": "",
    "client_x509_cert_url": "",
    "client_secret": "yoursecret",
    "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob", "http://tooltank.de"]
}}

正确的下载位置是创建新的客户端ID并选择已安装的应用程序。


那么,原始的kots.json有什么用?(我的意思是,它是创建客户端时自动下载的默认文件,所以我认为它在某个地方很有用?) - CasualT
1
我还没有找出它的用途,但有另一个选项可以下载JSON文件,格式与我的更新中所示相同。 - Jan Vladimir Mostert
在我的情况下,我正在使用服务帐户,所以它对我来说不太适用。 - CasualT
我以为我正在使用服务帐户,结果发现我错了。不确定服务帐户选项是用来做什么的,根据我遵循的任何教程,它下载的JSON文件都无法正常工作。 - Jan Vladimir Mostert
1
我最终只使用了pem或p12格式+“电子邮件”标识符。(所以我已经让它工作了,我只是好奇为什么他们会给我们下载一个基本上无法被他们的驱动程序读取的json选项)。 - CasualT
以下是下载JSON的确切步骤。凭直觉无法完成。https://developers.google.com/sheets/api/quickstart/java#step_1_turn_on_the_api_name - neeraj
2个回答

4
我遇到了同样的问题,这个问题与我从Google Cloud下载的原始JSON密钥文件有关。通过设置一个包含JSON密钥文件路径的环境变量,一切都可以正常工作。
set GOOGLE_APPLICATION_CREDENTIALS "secret.json path"

并运行此行代码:
GoogleCredential credential = GoogleCredential.getApplicationDefault();

但是当我想将我的秘密文件作为资源包含在我的项目中时,出现了像你这样的问题。

所以我最终发现这一简单的代码可以解决问题:

GoogleCredential credential =
    GoogleCredential.fromStream(MyClass.class.getResourceAsStream("/client_secrets.json"));

希望能帮到你。

2

实际上你不是,我也遇到了类似的谷歌云盘问题被骚扰,但这段代码对我起作用。我知道你会认为你的代码是一样的,但试试它吧。

private static final List<String> SCOPES =
            Arrays.asList(DriveScopes.DRIVE);
     @Override
        public Credential authorize() throws IOException {
            InputStream in =
                    DriveQuickstartImpl.class.getResourceAsStream("/client_secret.json");
            GoogleClientSecrets clientSecrets =
                    GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

            GoogleAuthorizationCodeFlow flow =
                    new GoogleAuthorizationCodeFlow.Builder(
                            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                            .setDataStoreFactory(DATA_STORE_FACTORY)
                            .setAccessType("online").setApprovalPrompt("auto")
                            .build();
            Credential credential = new AuthorizationCodeInstalledApp(
                    flow, new LocalServerReceiver()).authorize("user");
            if(credential!=null && credential.getRefreshToken() != null){
                storeCredentials(credential);
            }
           return credential;

        }

如果它不能正常工作,请告诉我,我会将其删除,我的client_secret在资源文件夹中。

让我在部署时间间隙尝试一下,然后再回复您,谢谢 Borg 先生。 - Jan Vladimir Mostert
1
好的,请将您的整个POM.xml粘贴在主帖或pastebin.com上。另外,您能否发布完整的日志。谢谢。 - We are Borg
我已经更新了问题,包括pom文件、源代码、堆栈跟踪以及反编译类的代码片段。 - Jan Vladimir Mostert
1
我希望你的JSON以“已安装”开头,而不是“WEB”... 我要休息一下,可能需要一些时间才能回来。 - We are Borg
1
让我们在聊天中继续这个讨论 - We are Borg
显示剩余2条评论

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