4

我是 Google API 的新手。我有一个使用自己的域注册的 google 工作区帐户。我希望能够使用 google java api 对用户邮箱执行操作。我正在使用快速启动项目并将身份验证用作范围。

我可以对执行了 OAuth 同意的用户帐户执行操作。

看例子

 String user = "me";
            ListLabelsResponse listResponse = service.users()
           .labels().list(user).execute();

它使用“我”关键字作为用户,我想使用帐户中的一个用户并执行相同的操作。当我将“我”切换到我域中的一个用户时,我得到以下信息。

GET https://gmail.googleapis.com/gmail/v1/users/user@somedomain.what.ever/labels
{
  "code" : 403,
  "errors" : [ {
    "domain" : "global",
    "message" : "Delegation denied for admin@mirncast.uk",
    "reason" : "forbidden"
  } ],
  "message" : "Delegation denied for admin@mirncast.uk",
  "status" : "PERMISSION_DENIED"
}

据我了解,我需要提供用户委托。用户委托需要服务帐户。所以我试着按照这个教程

我的代码最终成为

Set<String> scope = Collections.singleton(GmailScopes.MAIL_GOOGLE_COM);

GoogleCredential credentialFromJson = GoogleCredential
        .fromStream(new FileInputStream(
                "/certificate.json"))
       .createScoped(scope);

GoogleCredential credential = new GoogleCredential.Builder()
        .setTransport(httpTransport)
        .setJsonFactory(jsonFactory)
        .setServiceAccountId(credentialFromJson.getServiceAccountId())
        .setServiceAccountPrivateKey(credentialFromJson.getServiceAccountPrivateKey())
        .setServiceAccountScopes(Collections.singleton(GmailScopes.MAIL_GOOGLE_COM))
        .setServiceAccountUser("user@somedomain.what.ever")
        //.setServiceAccountUser("service@custom-octagon-1234567.iam.gserviceaccount.com")
        .build();


Gmail service = new Gmail.Builder(httpTransport, jsonFactory, credential).setApplicationName("remediation service").build();

String user = "user@somedomain.what.ever";
final var messagesResponse = service.users().messages().list(user).execute();
System.out.println(messagesResponse.getMessages().stream().map(message -> message.getId()).collect(Collectors.joining(",")));

这段代码有一些问题。

只有当我使用我尝试访问的相同电子邮件地址设置 setServiceAccountUser 时,我才能使其工作。从我的角度来看,以这种方式使用 API 会破坏目的。使用服务帐户时出现以下错误

Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
GET https://gmail.googleapis.com/gmail/v1/users/hraman@gsuite-dev.mirncast.uk/messages
{
  "code" : 400,
  "errors" : [ {
    "domain" : "global",
    "message" : "Precondition check failed.",
    "reason" : "failedPrecondition"
  } ],
  "message" : "Precondition check failed.",
  "status" : "FAILED_PRECONDITION"
}

该示例使用已弃用的 API GoogleCredential,我无法确定基于 OAuth2 身份验证的最新 API 是什么

我的 Maven 依赖项

<dependencies>
    <dependency>
        <groupId>com.google.apis</groupId>
        <artifactId>google-api-services-gmail</artifactId>
        <version>v1-rev20210301-1.31.0</version>
    </dependency>
    <dependency>
        <groupId>com.google.oauth-client</groupId>
        <artifactId>google-oauth-client-jetty</artifactId>
        <version>1.31.4</version>
    </dependency>
</dependencies>
4

1 回答 1

2

您首先需要了解gmail数据是私人用户数据,只有该数据的所有者才能访问该数据,或者已被用户授权访问该数据的应用程序。在gsuite域账户的情况下,域管理员也可以授予其他人冒充原始用户的权限,但冒充的仍然是访问数据的用户。它就像它的原始用户一样行事。(理解这个概念很快就会很重要)

您需要了解服务帐户只是一个虚拟用户。它有自己的 google drive 帐户和 google calendar 帐户,它还可以像拥有 gmail 帐户一样发送电子邮件。所以像你一样,它只能默认访问自己的私有数据。

现在使用 gsuite,我们可以委派用户权限,允许他们模拟另一个用户“user@somedomain.what.ever”

因此可以对其进行设置,以便"service@custom-octagon-1234567.iam.gserviceaccount.com"允许模拟"user@somedomain.what.ever"并代表他们执行操作。只有这样才能在代码中工作,您必须说明您当前正在模拟的用户,在这种情况下我们使用setServiceAccountUser如果您不这样做,那么您只是"service@custom-octagon-1234567.iam.gserviceaccount.com"并且只能访问属于的数据"service@custom-octagon-1234567.iam.gserviceaccount.com"

至于使用messages.list访问数据,以下命令是可以互换的。

service.users().messages().list("user@somedomain.what.ever")
service.users().messages().list("me")

如果第一个选项不是当前经过身份验证的用户的电子邮件地址或模拟用户,它将失败。通过模拟用户,您实际上就是该用户,因此 API 将服务帐户视为"user@somedomain.what.ever"没有指定模拟,您只是普通的旧服务帐户,只能访问其数据。

需要有一种方法来指定来自服务帐户的所有呼叫现在都代表该用户,这就是为什么您需要设置setServiceAccountUser为您希望模拟的用户的原因。

于 2021-03-25T08:50:22.050 回答