2

我们的 Marketplace 应用程序的一项功能是通过 IMAP 访问用户的 Gmail 帐户。我们在 java-gmail-imap 项目中使用了 google-api-java-client 和 google-oauth-java-client 库和类似于此示例的代码,如下所示:

GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
    .setJsonFactory(JSON_FACTORY)
    .setServiceAccountId(SERVICE_ACCOUNT_ID)
    .setServiceAccountScopes(Arrays.asList(GMAIL_SCOPE))
    .setServiceAccountPrivateKey(PRIVATE_KEY)
    .setServiceAccountUser(emailAddress)
    .build();
credential.refreshToken();

然后,我们使用基于https://code.google.com/p/google-mail-oauth2-tools示例的代码来建立 IMAP 连接,例如

IMAPStore imapStore = OAuth2Authenticator.connectToImap("imap.googlemail.com",
    993, emailAddress, credential.getAccessToken(), false);

大多数情况下,这似乎可以正常工作,但是我们看到,对于少量但大量的请求,对 Google 的调用refreshToken()失败并出现 HTTP 500 错误和 HTML 响应,其中 JSON 通常会返回,例如

<p class="large"><b>500.</b> <ins>That's an error.</ins></p>
<p class="large">The server could not process your request.
<ins>That's all we know.</ins></p>

Google 的一位开发人员倡导者告知我们,服务帐户不支持刷新令牌,我们应该使用本示例中的方法。

但是,似乎没有调用refreshTokenthenaccessToken不会填充在凭证对象上,然后这会导致NullPointerException我们调用OAuth2Authenticator.connectToImap

从源代码来看,GoogleCredential它似乎executeRefreshToken()被覆盖以处理服务帐户,即它不是执行刷新,而是简单地请求一个新令牌,然后这段代码Credential处理填充访问令牌:

TokenResponse tokenResponse = executeRefreshToken();
if (tokenResponse != null) {
    setFromTokenResponse(tokenResponse); ....

我们不确定是否需要将调用包含refreshToken()在重试循环中以解决间歇性 500 错误,或者是否需要对代码进行其他更改以遵循针对此场景的推荐方法。

任何人都可以建议吗?

4

1 回答 1

1

我在生产中使用java-gmail-imap 示例代码(但它仅用于在我们的大学门户中显示收件箱,没有太多交互需要我重用相同的刷新令牌)。

根据您的使用情况,我想知道在您的情况下是否会出现某种限制(我在Gmail 偶尔会限制访问的地方读到过)。

在其他地方,我看到 Google API 谈论使用指数退避算法进行重试。

在将 OAuth 2.0 的使用与其他 Google 服务 API 和 Gmail 进行比较时,您必须小心一点。Gmail 的特殊之处在于它使用 XOAUTH2。也就是说,我已经看到其他似乎需要refreshToken 调用的 Google API 。文档有点不清楚,并说“如有必要,请刷新访问令牌”(正如您所说,如果没有此步骤,它似乎无法正常工作,但我还没有通过凭据重新使用刷新令牌进行任何实验。设置刷新令牌(字符串刷新令牌))。

我很想听听你过得怎么样。

于 2014-04-01T22:14:11.200 回答