首先,让我解释一下我想要做什么,因为这是一个两部分的问题。
我正在构建一个JAX-RS服务,它通过OAuth2在内部验证Google帐户,这样它就可以访问和操作Google日历。这项服务将由一个网站(Joomla)调用,它将允许登录该网站的用户在日历事件中注册他们的电子邮件地址,这样当事件临近时,他们就可以收到电子邮件通知。这些用户不知道底层的Google帐户。
因此,我的第一个问题是,使用服务帐户身份验证是正确的吗?看看Google文档,它是唯一适合非人工身份验证的用例(即服务器到服务器的身份验证)。
第二个问题是,我已经编写了一些代码来做这件事,但是当我调用execute方法Calendar提要时,我得到了一个401/Unauthorized响应,返回了以下错误。这段代码取自Google示例。
我使用的是Google Calendar API的v3-rev3-1.5.0-beta。我已经在帐户中打开了Calendar API,并创建并下载了一个私钥,该私钥在下面的代码中使用。
我在Eclipse中本地调用下面的代码,而不是从web服务器调用。
因此,我进行的第一个调用是返回一个凭据对象(Id用X混淆):
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
.
.
.
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("284XXXXXXXX@developer.gserviceaccount.com")
.setServiceAccountScopes(CalendarScopes.CALENDAR)
.setServiceAccountPrivateKeyFromP12File(new File("D:/3cd8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXd635e-privatekey.p12"))
.build();
下一步是调用Calendar API,如下所示(中间不调用其他代码):
Calendar calendar = Calendar.builder(HTTP_TRANSPORT, JSON_FACTORY)
.setApplicationName("TestApp-Calendar/1.0").setHttpRequestInitializer(credential)
.build();
CalendarList feed = calendar.calendarList().list().execute();
调用list().execute()会导致以下错误:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized {“代码”:401,“错误”:{“域”:“全局”,“位置”:“授权”,"locationType“:”头“,”消息“:”需要登录“,”原因“:”必须“},"message“:”需要登录“} at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:159) at com.google.api.client.googleapis.json.GoogleJsonResponseException.execute(GoogleJsonResponseException.java:187) at com.google.api.client.googleapis.services.GoogleClient.executeUnparsed(GoogleClient.java:115) at com.google.api.client.http.json.JsonHttpRequest.executeUnparsed(JsonHttpRequest.java:112)at com.google.api.services.calendar.Calendar$CalendarList$List.execute(Calendar.java:510) at uk.org.reigatepriorybowmen.Service.registerEmailForAllCalendarEvents(Service.java:55) at uk.org.reigatepriorybowmen.Service.main(Service.java:74)
服务帐号设置如下:
那么,我到底做错了什么?!我花了几个小时在谷歌上寻找解决方案,所以这是我最后的希望。
非常感谢您的帮助。
贾斯汀
发布于 2012-08-07 13:41:37
至于401,谷歌的API似乎有些奇怪。我发现我在一段时间内第一次运行我的应用程序,然后以看似随机的时间间隔,我总是得到401。在第二轮或第三轮时,它实际上登录了。
这种行为甚至在谷歌的Task API示例代码here中也有说明。
请注意以下代码:
void onRequestCompleted() {
received401 = false;
}
void handleGoogleException(IOException e) {
if (e instanceof GoogleJsonResponseException) {
GoogleJsonResponseException exception = (GoogleJsonResponseException) e;
if (exception.getStatusCode() == 401 && !received401) {
received401 = true;
accountManager.invalidateAuthToken(credential.getAccessToken());
credential.setAccessToken(null);
SharedPreferences.Editor editor2 = settings.edit();
editor2.remove(PREF_AUTH_TOKEN);
editor2.commit();
gotAccount();
return;
}
}
Log.e(TAG, e.getMessage(), e);
}
在谷歌自己的代码样本中,他们第一次提供了401。它可能是一些特殊的安全问题,需要在代码中处理。
发布于 2012-05-05 08:32:32
我认为您需要指定您尝试模拟的用户。
您现在使用ServiceAccount的方式仅适用于访问与您的应用程序或您的服务帐户本身相关的数据。由于您希望访问Google Calendar数据,因此您必须是Google Apps域管理员,有权访问您的任何域用户的数据-如果我的数据不正确,请让我知道。Google Calendar数据属于用户,因此您需要指定您尝试模拟的用户。
要使用Java完成此操作,似乎需要使用GoogleCredential.Builder#setServiceAccountUser(String)
请尝试:
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("284XXXXXXXX@developer.gserviceaccount.com")
.setServiceAccountScopes(CalendarScopes.CALENDAR)
.setServiceAccountPrivateKeyFromP12File(new File("/path/to/privatekey.p12"))
.setServiceAccountUser("user@domain.com")
.build();
此外,一旦您在您的应用程序接口项目中创建了服务帐户密钥(从API控制台),您必须将此项目添加到cPanel中授权的第三方应用程序列表中。有关这方面的更多信息,请访问here。您需要使用的“客户端Id”是绑定到服务帐户密钥的Id,看起来像<APP_ID>-<OTHER_KEY>.apps.googleusercontent.com
发布于 2012-06-28 06:16:58
如果您没有在管理面板中添加api用户(在您的情况下文档面板,我猜),例如在google analytics中,您必须添加新用户,其中电子邮件地址与您从api获得的地址相同(由Google API服务帐户在创建私钥后提供)。在分析中,它看起来像这样:
https://stackoverflow.com/questions/10112939
复制相似问题