通过 OAuth 2.0 和私钥(即服务帐户)访问 Google Contacts Api

Posted

技术标签:

【中文标题】通过 OAuth 2.0 和私钥(即服务帐户)访问 Google Contacts Api【英文标题】:Accessing Google Contacts Api via OAuth 2.0 and private key aka Service Account 【发布时间】:2013-01-02 15:57:04 【问题描述】:

我目前正在通过 OAuth 2.0 和所谓的服务帐户实现对 Google 通讯录的访问。服务帐号是为“My.Name@gmail.com”这样的普通用户生成的。

生成 OAuth 2.0 凭据的代码是:

public static GoogleCredential getCredentials() throws GeneralSecurityException, IOException 
    GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
            .setJsonFactory(JSON_FACTORY)
            .setServiceAccountId(SingleUserCredentials.SERVICE_ACCOUNT_EMAIL)
            .setServiceAccountScopes("https://www.google.com/m8/feeds")
            .setServiceAccountPrivateKeyFromP12File(new File(SingleUserCredentials.SERVICE_ACCOUNT_PKCS12_FILE_PATH))
            .build();
    credential.refreshToken();
    return credential;

然后我尝试通过以下方式检索联系人:

    ContactsService myService = new ContactsService(
            "myApp");

    myService.setOAuth2Credentials(getCredentials());

    URL feedUrl = new URL("https://www.google.com/m8/feeds/contacts/default/full");
    Query myQuery = new Query(feedUrl);
    ContactFeed resultFeed = myService.query(myQuery, ContactFeed.class);
    // Print the results

    for (ContactEntry entry : resultFeed.getEntries()) 
        System.out.println(entry.getName().getFullName().getValue());
        System.out.println("Updated on: " + entry.getUpdated().toStringRfc822());
    

问题是我没有从我的帐户中获得任何联系人。提要始终为空。没有错误。没有。

当通过相同的方法访问 Google Apps 托管域时,它运行良好。

我想知道在使用 p12 密钥文件和服务帐户时,Contacts Api 是否支持普通(又名@gmail.com)帐户的 OAuth 2.0。

【问题讨论】:

【参考方案1】:

我自己也遇到了同样的问题。

我尝试了设置密钥时收到的电子邮件地址和域管理员的电子邮件地址。

当我使用密钥设置中的电子邮件时,我什么都没有收到 - 没有警告、没有异常,也没有数据。

当我使用域管理员的电子邮件地址时,我收到异常:

com.google.api.client.auth.oauth2.TokenResponseException: 400 OK
     [java] 
     [java]   "error" : "invalid_grant"
     [java] 
     [java] Feb 5, 2013 5:16:48 PM com.google.appengine.repackaged.org.apache.http.impl.client.DefaultRequestDirector handleResponse
     [java] WARNING: Authentication error: Unable to respond to any of these challenges: 
     [java] Feb 5, 2013 5:16:48 PM com.google.apphosting.utils.jetty.JettyLogger warn
     [java] WARNING: /
     [java] java.lang.NullPointerException: No authentication header information

...

所以,我认为域管理员的电子邮件地址不是我需要的。

接下来,我在谷歌上搜索了一段时间才找到这个页面:

http://javadoc.google-api-java-client.googlecode.com/hg/1.13.2-beta/com/google/api/client/googleapis/auth/oauth2/GoogleCredential.html

我在那里看到了getServiceAccountUser()。该字段的描述是:

返回应用程序尝试在服务帐户流中模拟的用户的电子邮件地址,或者返回 null 表示无或不使用服务帐户流。

果然,有一个对应的 setServiceAccountUser (String) 接受你正在使用服务帐户模拟的用户的用户名(电子邮件地址)。

我将该字段设置为适当的值并且我能够继续。

回想起来,这一切都是有道理的——如果我不提供我正在尝试使用的帐户,我就无法删除该帐户的联系人。

【讨论】:

您好匿名,感谢您的回答。但是,您正在描述基于密钥的 OAuth 2.0 访问域的方法。如上所述,这对我来说很好。我真正想要的是一种通过像 My.Name@gmail.com 这样的普通用户访问联系人的解决方案——没有谷歌管理的域。我希望我上面的问题在这方面有意义。【参考方案2】:

目前无法使用服务帐户访问联系人,因为在 Google APIs Console 的 Google API 控制台中不支持该帐户。

另见:Service Accounts

其次,它仅适用于 Google 托管域,因为域的管理员必须通过以下过程授予对服务帐户的访问权限:

将域范围的权限委派给您的服务帐户

您现在创建的服务帐户需要被授予访问您想要访问的 Google Apps 域的用户数据的权限。以下任务必须由 Google Apps 域的管理员执行:

    转到您的 Google Apps 域的控制面板。该网址应如下所示:“www.google.com/a/cpanel/mydomain.com”

    转到高级工具... > 管理第三方 OAuth 客户端访问。

    在“客户名称”字段中输入服务帐户的客户 ID。

    在一个或多个 API 范围字段中,输入应授予您的应用程序访问权限的范围列表。

    点击授权按钮。

【讨论】:

不确定我是否同意。联系人 API 在域的 API 控制台中也不可用 - 但它适用于域。所以理论上这也应该适用于普通的 gmail 帐户。关于服务帐户-该概念适用于单个帐户。我们使用 Calendar Api 和 Drive 对其进行了测试。最后 - 真正奇怪的是我们没有收到任何失败消息。我们只得到没有数据。看起来更像是一个错误? 我在找到这个答案之前尝试了这种方法,但对我来说它不起作用。我正在使用 - 作为范围 - https://www.google.com/m8/feeds(联系人 R/W)但没有喜悦。我注意到服务的范围被“识别”了,并且它们的人性化名称显示在 URI 旁边,但是上面的不会发生这种情况。我怀疑它根本不受支持。 @mac 我遇到了同样的情况,这个 URL 无法识别。但是,如果您在末尾添加一个斜线,它就会被识别。 (虽然没有实际调用 API 的运气......)【参考方案3】:

我今天遇到了同样的错误,但现在已经放弃使用服务帐户,我认为联系人 API 目前不支持。因此,我将 Contacts API v3 与 OAuth 1.0 一起使用,并获得了预期的结果。

 ContactsService contactsService = new ContactsService(APPLICATION_NAME);
 contactsService.setUserCredentials(CLIENT_USERNAME, CLIENT_SECRET);

 URL contactFeedURL = new URL("https://www.google.com/m8/feeds/contacts/default/full");
 Query contactFeedQuery = new Query(contactFeedURL);

 ContactFeed contactFeed = contactsService.getFeed(contactFeedQuery, ContactFeed.class);

【讨论】:

谢谢 :) 很高兴知道。 OAuth 1.0 也适用于我们。 OAuth 2.0 仍然不适用于 p12 证书... 希望它能尽快得到支持。我知道这没有回答您的问题,但我认为它可能对希望开始使用通讯录的人有用。

以上是关于通过 OAuth 2.0 和私钥(即服务帐户)访问 Google Contacts Api的主要内容,如果未能解决你的问题,请参考以下文章

Google OAuth 2.0 服务帐户 - 日历 API(PHP 客户端)

通过OAuth 2.0令牌撤销提高帐户安全性

使用服务帐户通过 OAuth 2.0 调用 v3 Google 日历 API 时出现“需要登录”401 未经授权的消息

请问SSL加密的公钥和私钥区别

服务帐户的 google OAuth 2.0 是 OAuth 2.0 标准的一部分吗?

检测证书和私钥是否匹配的办法你知道吗