如何为 Google 联系人 API 验证 java 应用程序?

How to authenticate a java application for the Google Contacts API?

我有一个 java 应用程序 运行 几年了,它可以将某些数据库中的一些联系人同步到客户的 gmail 帐户中。

这几天前就停止工作了,大概是因为 Google stopped supporting 简单的 username/password 身份验证。

第一个问题:我假设现在唯一支持的身份验证是 OAuth2 是否正确?

假设是这样,我不明白我应该使用什么样的授权scheme/flow。我无法显示对话框 - 这是一种服务类型的应用程序,它应该只能访问我控制的一个特定客户帐户。我想我应该使用 Service Account,但文档是这样说的:

Typically, an application uses a service account when the application uses Google APIs to work with its own data rather than a user's data.

但我想使用用户数据 - 特别是联系人。

对于那种情况,文档是这样说的:

If you have a Google Apps domain—if you use Google Apps for Work, for example—an administrator of the Google Apps domain can authorize an application to access user data on behalf of users in the Google Apps domain. For example, an application that uses the Google Calendar API to add events to the calendars of all users in a Google Apps domain would use a service account to access the Google Calendar API on behalf of users. Authorizing a service account to access data on behalf of users in a domain is sometimes referred to as "delegating domain-wide authority" to a service account.

但是,我没有 Google 应用程序域。

那么……现在怎么办?

第一个问题:我假设现在唯一支持的身份验证是 OAuth2 是否正确?

那么...现在怎么办?

与用户名密码最接近的类比是刷新令牌(它只是一个字符串)。即:-

  • 如果您的应用有刷新令牌,它可以随时访问授予它的资源
  • 由于刷新令牌的强大功能,它需要像密码一样安全存储

此处描述了获取刷新令牌所需的步骤How do I authorise an app (web or installed) without user intervention? (canonical ?)

该答案还包含一个 link,它指向 Google 文档,了解如何使用刷新令牌获取访问令牌。

这里是一些代码(基于 pinoyyid 的建议):

String CLIENT_ID = "see instructions in accepted answer";
String CLIENT_SECRET = "see instructions in accepted answer";
String REFRESH_TOKEN = "see instructions in accepted answer";

Builder builder = new GoogleCredential.Builder();
builder.setTransport(GoogleNetHttpTransport.newTrustedTransport());
builder.setJsonFactory(JacksonFactory.getDefaultInstance());
builder.setClientSecrets(CLIENT_ID, CLIENT_SECRET);

Credential credential = builder.build();
credential.setRefreshToken(REFRESH_TOKEN);
credential.refreshToken(); // gets the access token, using the refresh token

ContactsService contactsService.setOAuth2Credentials(credential);

Query query = new Query(new URL("https://www.google.com/m8/feeds/contacts/default/full"));
query.setMaxResults(10_000);

ContactFeed allContactsFeed = contactsService.getFeed(query, ContactFeed.class);

LOGGER.log(Level.INFO, allContactsFeed.getTitle().getPlainText());

for(ContactEntry contact : allContactsFeed.getEntries())
{
  ...
}