Google通讯录API - 无法刷新访问令牌 [英] Google Contacts API - failing to refresh access token

查看:148
本文介绍了Google通讯录API - 无法刷新访问令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们使用Google Contacts API和OAuth2:

 凭证=新的GoogleCredential.Builder()。setTransport(new NetHttpTransport() )
.setJsonFactory(new JacksonFactory())
.setClientSecrets(OAuth2ClientId(),OAuth2ClientSecret())
.addRefreshListener(new CredentialRefreshListener(){...});

myService = new ContactsService(My-App);
myService.setOAuth2Credentials(凭证);

,并且经常收到GData库无法处理的'401 Unauthorized'响应。
当缺少 WWW-Authenticate 标题时,AuthenticationException抛出NPE。

 由于:java.lang.NullPointerException:没有认证头信息
在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]
在com.google.gdata.client上的com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:608)〜[gdata-core-1.0-1.47.1.jar:na]
。 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]
,位于com.google.gdata.client.Service.getFeed(Service.java:1135)〜[gdata-core-1.0-1.47.1.jar:1.47.1]
,位于com.google.gdata.client.Service.getFeed(Service.java:1077)〜[gdata-core-1.0-1.47.1.jar:1.47.1]
。 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()时, code> executeRefreshToken()被执行时没有出现异常,但是返回了 tokenResponse == null 。结果 refreshToken()返回 false ,没有任何理由被传递给监听者

  try {
TokenResponse tokenResponse = executeRefreshToken();
if(tokenResponse!= null){
setFromTokenResponse(tokenResponse);
for(CredentialRefreshListener refreshListener:refreshListeners){
refreshListener.onTokenResponse(this,tokenResponse);
}
返回true;

} catch(TokenResponseException e){
boolean statusCode4xx = 400< = e.getStatusCode()&& e.getStatusCode()< 500;
//检查它是否为正常错误响应
if(e.getDetails()!= null&& statusCode4xx){
//我们无法获得新的访问令牌(例如它可能已被撤销),我们现在必须
//表明我们当前的标记是无效的。
setAccessToken(null);
setExpiresInSeconds(null);

for(CredentialRefreshListener refreshListener:refreshListeners){
refreshListener.onTokenErrorResponse(this,e.getDetails());
}
if(statusCode4xx){
throw e;
}
}
返回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

解决方案

目前联系人API中存在一个错误, HTTP User-Agent 字符串,导致401响应返回为HTML页面而不是XML响应,并且缺少 WWW-Authenticate 头部, AuthenticationException 类依赖于。 GContacts-Java 是这些特殊用户代理字符串之一。解决方法是在创建客户端后更改客户端的用户代理:

  ContactsService服务= new ContactsService(applicationName); 
service.getRequestFactory()。setHeader(User-Agent,applicationName);

这应该消除NPE,并允许客户端库自动检测到过期的令牌并自动刷新它们。

We use Google Contacts API with 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);

and quite regularly we receive '401 Unauthorized' response that the GData library can't handle. AuthenticationException throws NPE when WWW-Authenticate header is missing.

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]

We managed to add a wrapper that would try token refreshing on this NPE. It helps but then there are still many cases when refreshing fails:

credential.refreshToken() == false

When we run refreshToken() in the debugger we see that executeRefreshToken() is executed without an exception but tokenResponse==null is returned. As a result refreshToken() returns false and no reason is passed to the listeners

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;

Our tokens are always for multiple scopes: 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

解决方案

There is currently a bug in the Contacts API where certain HTTP User-Agent strings, cause the 401 response to return as an HTML page instead of an XML response, and missing the WWW-Authenticate header that the AuthenticationException class is relying on. GContacts-Java is one of these special user agent strings. A workaround is to change the user agent of your client after you create it:

ContactsService service = new ContactsService(applicationName);
service.getRequestFactory().setHeader("User-Agent", applicationName);

This should eliminate the NPE, and allow the client library to automatically detect expired tokens and refresh them automatically.

这篇关于Google通讯录API - 无法刷新访问令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆