首先,让我解释什么,我试图做的,因为这是一个问题的两个部分。
我建立在内部通过的OAuth2一个谷歌帐户验证一个JAX-RS的服务,所以它可以访问和操作谷歌日历。 这项服务将通过一个网站(的Joomla),这将允许登录到网站的用户注册与日历事件他们的电子邮件地址,以便他们可以得到电子邮件通知当事件附近被调用。 这些用户有没有潜在的谷歌帐户的知识。
所以我的第一个问题,是使用服务帐户验证正确的事情? 纵观谷歌文档,它的唯一使用情况非人认证迎合(这样服务器到服务器身份验证)。
第二个问题是,我已经写了一些代码来做到这一点,但我拿回401 /未经授权的响应返回以下错误回来时,我调用execute方法日历饲料。 此代码从谷歌的样品被解除。
我使用的谷歌日历API的V3-rev3-1.5.0-β。 我在帐户中打开日历API,以及创建并下载一个专用密钥,也就是下面的代码中使用。
我在Eclipse中调用下面的代码在本地,而不是从Web服务器。
所以,第一个电话我提出的是要回凭据对象(标识与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();
接下来的步骤是,以再调用日历API,像这样(无称为之间其他码):
Calendar calendar = Calendar.builder(HTTP_TRANSPORT, JSON_FACTORY)
.setApplicationName("TestApp-Calendar/1.0").setHttpRequestInitializer(credential)
.build();
CalendarList feed = calendar.calendarList().list().execute();
到列表())的调用执行(导致以下错误:
com.google.api.client.googleapis.json.GoogleJsonResponseException:401未授权{ “代码”:401, “错误”:[{ “域”: “全局”, “位置”: “授权”, “的locationType”:“头”, “消息”: “需要登录”, “理由”: “需要”}], “消息:在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)在英国.org.reigatepriorybowmen.Service.registerEmailForAllCalendarEvents(Service.java:55)在uk.org.reigatepriorybowmen.Service.main(Service.java:74)
该服务帐户的设置如下:
所以,我在做什么错? 我花了几个小时谷歌搜索四处寻找解决方案,所以这是我最后的希望。
许多在此先感谢您的帮助。
贾斯汀
Answer 1:
至于401,似乎有些古怪与谷歌的API。 我在第一时间发现我跑我的应用程序在一段时间,然后在看似随机时间间隔分开小时,我总是得到401在它实际上在记录第二轮或第三轮。
该行为即使是在谷歌的任务API的示例代码占了这里 。
注意下面的代码:
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这可能是需要一些特殊的安全问题,要在代码来处理作出了规定。
Answer 2:
其中电子邮件地址是你从API得到了同样的,如果你没有在管理面板中添加的API的用户(在你的案件文档面板我猜的),例如在您需要添加新的用户谷歌分析,可能会出现这样的行为(由提供谷歌API服务帐户,创建私有密钥后)。 在分析它看起来像这样:
Answer 3:
我想你会需要指定您要模拟用户。
您正在使用ServiceAccount现在的方式是唯一有效的与您的应用程序或服务帐户本身的访问数据。 既然你想要访问谷歌日历数据,你必须是一个谷歌Apps域管理员提供访问权限的任何域用户的数据 - 让我知道,如果我是不正确的。 谷歌日历数据属于用户,所以你需要指定你想模仿哪个用户。
要做到使用Java这样,看来你需要做的使用GoogleCredential.Builder#setServiceAccountUser(字符串)
请试试:
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”你需要使用的是一个绑定到服务帐户键,看起来像<APP_ID>-<OTHER_KEY>.apps.googleusercontent.com
Answer 4:
我是一个Android移动应用开发者。 我正在使用谷歌日历API(OAuth 2.0用户)的应用程序。 我也面临着同样的错误。 但现在,我已经解决了这个错误。 我写的方案,并为它的解决方案。
得到的特定日历(移动应用API)日历活动的网址:
https://www.googleapis.com/calendar/v3/calendars/en.indian%23holiday%40group.v.calendar.google.com/events?access_token=ya29.AHES6ZQyP3iDZM8PF-7ZqZE8oKmWAgUX55sPGPTjGbM5A
在此网址,我们必须添加calendarId。 URL的格式;
https://www.googleapis.com/calendar/v3/calendars/<calendarId>/events
我没有添加到URL编码前的calendarId。 余编码的calendarId然后作出的HTTP请求。 所有的都很好,然后。
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;
现在日历事件在JSON返回。
Answer 5:
好了,我一直在玩这个周围,并已得到了以往的401错误,但我现在打一个403不过,我会详细的代码我写了至少回答401问题。
我没有改变任何的服务帐户设置或重新生成任何按键等,这是完全一样的。
什么东西有变化是一些代码,并且我升级到v3r20lv1.12.0-β日历API的。
如在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);
在这一点上,我可以通过我的日历迭代,看到的事件,通过运行下面的代码(本打印的事件总结):
Events events = calendar.events().list(CALENDAR_ID).execute();
for (Event event : events.getItems())
{
System.out.println(event.getSummary());
}
但是,如果我尝试更新的事件,我得到一个403 Forbidden错误。 我会提出一个单独的线程这一点,并且将两个线程联系在一起。
感谢大家的帮助!
编辑: 这里是新的线程。
Answer 6:
你的正确范围请求允许吗? 你应该总是包括https://www.googleapis.com/auth/userinfo.profile
文章来源: “Login Required” 401 Unauthorized message when calling the v3 Google Calendar API using a Service Account via OAuth 2.0