Oauth 2.0 &引用;“需要登录”;401通过OAuth 2.0使用服务帐户调用v3 Google日历API时出现未经授权的消息
首先,让我解释一下我想做什么,因为这是一个由两部分组成的问题 我正在构建一个JAX-RS服务,该服务通过OAuth2对Google帐户进行内部身份验证,因此它可以访问和操作Google日历。该服务将由一个网站(Joomla)调用,该网站将允许登录该网站的用户在日历事件中注册其电子邮件地址,以便在事件临近时获得电子邮件通知。这些用户不知道底层的Google帐户 所以我的第一个问题是,使用服务帐户身份验证是正确的吗?看看谷歌文档,它是唯一一个满足非人工身份验证(服务器到服务器身份验证)的用例 第二个问题是,我已经编写了一些代码来实现这一点,但是当我调用execute方法Calendar feed时,返回了401/Unauthorized响应,返回了以下错误。这段代码是从Google示例中提取的 我使用的是谷歌日历API的v3-rev3-1.5.0-beta版。我已经打开了帐户中的日历API,创建并下载了一个私钥,该私钥在下面的代码中使用 我在Eclipse中本地调用下面的代码,而不是从web服务器调用 因此,我做的第一个调用是获取凭证对象(Id被X混淆): 下一步是调用日历API,如下所示(其间没有调用其他代码): 调用list().execute()会导致以下错误: com.google.api.client.googleapis.json.googlejson响应异常:401未经授权 { “代码”:401, “错误”:[{ “域”:“全局”, “位置”:“授权”, “位置类型”:“标题”, “消息”:“需要登录”, “原因”:“必需” } ], “消息”:“需要登录” } 位于com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:159) 位于com.google.api.client.googleapis.json.GoogleJsonResponseException.execute(GoogleJsonResponseException.java:187) 位于com.google.api.client.googleapis.services.GoogleClient.executeUnparsed(GoogleClient.java:115) 位于com.google.api.client.http.json.JsonHttpRequest.executeUnparsed(JsonHttpRequest.java:112) 位于com.google.api.services.calendar.calendar$CalendarList$List.execute(calendar.java:510) 在uk.org.reigatepriorybowmen.Service.registerEmailForAllCalendarEvents上(Service.java:55) 位于uk.org.reigatepriorybowmen.Service.main(Service.java:74) 服务帐户的设置如下所示: 那么,我做错了什么?!我花了几个小时在谷歌上搜索解决方案,所以这是我最后的希望 非常感谢你的帮助Oauth 2.0 &引用;“需要登录”;401通过OAuth 2.0使用服务帐户调用v3 Google日历API时出现未经授权的消息,oauth-2.0,google-calendar-api,google-oauth,google-api-java-client,Oauth 2.0,Google Calendar Api,Google Oauth,Google Api Java Client,首先,让我解释一下我想做什么,因为这是一个由两部分组成的问题 我正在构建一个JAX-RS服务,该服务通过OAuth2对Google帐户进行内部身份验证,因此它可以访问和操作Google日历。该服务将由一个网站(Joomla)调用,该网站将允许登录该网站的用户在日历事件中注册其电子邮件地址,以便在事件临近时获得电子邮件通知。这些用户不知道底层的Google帐户 所以我的第一个问题是,使用服务帐户身份验证是正确的吗?看看谷歌文档,它是唯一一个满足非人工身份验证(服务器到服务器身份验证)的用例 第二个
Justin我认为您需要指定您试图模拟的用户 您现在使用ServiceAccount的方式仅对访问与您的应用程序或服务帐户本身相关的数据有效。由于您希望访问谷歌日历数据,您必须是谷歌应用程序域管理员,具有访问任何域用户数据的权限-如果我不正确,请告诉我。谷歌日历数据属于用户,因此您需要指定您试图模拟的用户 要使用Java实现这一点,似乎需要使用 请尝试:
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项目中(从API控制台)创建了服务帐户密钥,您就必须将该项目添加到cPanel中授权的第三方应用程序列表中。有关这方面的更多信息可以找到。您需要使用的“客户端Id”是绑定到服务帐户密钥的Id,看起来像
-.apps.googleusercontent.com
如果您没有在“管理”面板(我想在您的案例中是“文档”面板)中添加api用户,则可能会发生这种行为,例如,在google analytics中,您必须添加新用户,其中电子邮件地址与您从api获得的地址相同(由google api服务帐户在创建私钥后提供)。
在分析中,它看起来是这样的:
至于401,谷歌的API似乎有些奇怪。我发现我第一次运行我的应用程序是在一段时间内,然后在看似随机的时间间隔里,我总是得到一个401。在第二轮或第三轮,它实际登录 这种行为甚至在谷歌的TaskAPI示例代码中得到了解释 请注意以下代码:
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错误,但我现在遇到了403。然而,我将详细说明我所写的代码,至少可以回答401问题 我没有更改任何服务帐户设置或重新生成任何密钥等,这一切都是一样的 改变的是一些代码,我升级到了日历API的v3r20lv1.12.0-beta版 如上文OP中所述,以下代码保持不变,即:
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();
获取日历句柄的代码已更改,但这是由API更改强制执行的:
Calendar calendar = new Calendar(HTTP_TRANSPORT, JSON_FACTORY, credential);
此时,通过运行以下代码(这将打印事件摘要),我可以遍历日历并查看事件:
但是,如果我尝试更新一个事件,我会得到一个403禁止的错误。我将为此提出一个单独的线程,并将这两个线程链接在一起
谢谢大家的帮助
编辑:是新线程。我是安卓移动应用程序开发人员。我正在使用GoogleCalendarAPI(OAuth2.0)制作一个应用程序。我也面临着同样的错误。但是现在,我已经解决了这个错误。我正在编写场景和解决方案。
获取特定日历的日历事件的url(移动应用程序API): 在这个城市
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 calendar = new Calendar(HTTP_TRANSPORT, JSON_FACTORY, credential);
Events events = calendar.events().list(CALENDAR_ID).execute();
for (Event event : events.getItems())
{
System.out.println(event.getSummary());
}
https://www.googleapis.com/calendar/v3/calendars/en.indian%23holiday%40group.v.calendar.google.com/events?access_token=ya29.AHES6ZQyP3iDZM8PF-7ZqZE8oKmWAgUX55sPGPTjGbM5A
https://www.googleapis.com/calendar/v3/calendars/<calendarId>/events
final String accessToken=dataStore.getAccessToken();
List<NameValuePair> params = new LinkedList<NameValuePair>();
params.add(new BasicNameValuePair("access_token", accessToken));
String paramString = URLEncodedUtils.format(params, "utf-8");
final String url = String.format(AuthConstants.CALENDAR_EVENTS_URI,URLEncoder.encode(calendarId))+"?"+ paramString;