【发布时间】:2014-12-04 20:28:10
【问题描述】:
我们将 Google Contacts API 与 OAuth2 结合使用:
credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
.setJsonFactory(new JacksonFactory())
.setClientSecrets(OAuth2ClientId(), OAuth2ClientSecret())
.addRefreshListener(new CredentialRefreshListener() {...});
myService = new ContactsService("My-App");
myService.setOAuth2Credentials(credential);
我们经常收到 GData 库无法处理的“401 Unauthorized”响应。
当WWW-Authenticate 标头丢失时,AuthenticationException 会抛出 NPE。
Caused by: java.lang.NullPointerException: No authentication header information
at com.google.gdata.util.AuthenticationException.initFromAuthHeader(AuthenticationException.java:96) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.util.AuthenticationException.<init>(AuthenticationException.java:67) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:608) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:564) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:560) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:538) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:536) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.Service.getFeed(Service.java:1135) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
at com.google.gdata.client.Service.getFeed(Service.java:1077) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
at com.google.gdata.client.GoogleService.getFeed(GoogleService.java:676) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
at com.google.gdata.client.Service.query(Service.java:1237) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
at com.google.gdata.client.Service.query(Service.java:1178) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
我们设法添加了一个包装器,可以尝试在此 NPE 上刷新令牌。它有帮助,但是刷新失败的情况仍然很多:
credential.refreshToken() == false
当我们在调试器中运行refreshToken() 时,我们看到executeRefreshToken() 没有异常地执行,但返回了tokenResponse==null。结果refreshToken() 返回false 并且没有向侦听器传递任何原因
try {
TokenResponse tokenResponse = executeRefreshToken();
if (tokenResponse != null) {
setFromTokenResponse(tokenResponse);
for (CredentialRefreshListener refreshListener : refreshListeners) {
refreshListener.onTokenResponse(this, tokenResponse);
}
return true;
}
} catch (TokenResponseException e) {
boolean statusCode4xx = 400 <= e.getStatusCode() && e.getStatusCode() < 500;
// check if it is a normal error response
if (e.getDetails() != null && statusCode4xx) {
// We were unable to get a new access token (e.g. it may have been revoked), we must now
// indicate that our current token is invalid.
setAccessToken(null);
setExpiresInSeconds(null);
}
for (CredentialRefreshListener refreshListener : refreshListeners) {
refreshListener.onTokenErrorResponse(this, e.getDetails());
}
if (statusCode4xx) {
throw e;
}
}
return false;
我们的令牌始终适用于多个范围:https://www.googleapis.com/auth/userinfo.email https://www.google.com/m8/feeds https://www.googleapis.com/auth/calendar https://mail.google.com/ https://www.googleapis.com/auth/tasks
更新:我们已成功迁移到 People API,新的 API 也被我们的统一 API 联系人 API https://docs.aurinko.io/article/25-contacts-api使用。
【问题讨论】:
-
澄清一下,有时刷新有效,但有时无效?一旦刷新停止工作,它会再次工作吗? AKA,它是临时状态还是永久状态?
-
好的,我们已经对此进行了更多试验。联系人与日历和任务的行为似乎有点不同。看起来 Calendar&Tasks credential.refreshToken() 可能会无缘无故地失败,但如果您等待并重试,它实际上可能会刷新令牌。对于联系人,它是 NPE“无身份验证标头信息”,但如果您在某些情况下再次尝试,它最终会刷新令牌,而在其他情况下,它总是会失败。
-
我正在解决这个问题。我当然看到 NPE 被抛出,但仍在努力让刷新失败。
-
Eric 我更新了这个问题。您希望我可以与您分享一组访问/刷新令牌,这些令牌经常发生。我想知道令牌刷新是否受到谷歌的速率限制,因为如果我们尝试更多次刷新,我们通常最终会成功。
-
这可能是一个单独的问题,但我也注意到对于 Gmail/IMAP XOAUTH,Gmail/IMAP 经常拒绝新刷新的令牌。感觉刷新的令牌没有足够快地传播到 Gmail 服务器,当我们尝试使用它时他们还不知道它。同样,我们在使用令牌之前放置了一些包装器,这似乎有帮助。所以总的来说,我们的令牌刷新过程现在被包装到我们处理 NPE、重试然后等待然后再次重试的代码中。不是很优雅。
标签: google-api google-oauth google-contacts-api google-data-api