无效凭证:Google API日历



我是使用Google api的新手。我按照步骤使用Google客户端库在eclipse中设置Google Calendar示例代码。我使用cmd命令- mvn appengine:update将代码部署到应用引擎(当试图通过eclipse部署时,它给了我一个错误,说该项目不是应用引擎项目)。通过命令行部署工作,我可以启动我的web应用程序。

突然,在几个API请求调用后,开始获得无效凭据错误:

错误:401
域:全球
位置:authorization
Locationtype: header
消息:无效凭据
原因:验证错误

我搜索了此错误,发现如果您的验证令牌无效或过期,可能会发生此错误。我不确定我需要做什么来获得一个新的验证令牌。在我的例子中,有一个client_secrets。Json文件,其中包含客户端秘密。我没有在代码的任何地方放置/保存或使用验证令牌。以下是我第一次部署代码时的记忆:

  • 有一些令牌,当我使用命令行部署时,我被要求粘贴在cmd上。之后,我可以启动我的应用程序。
  • 此后,每当我部署代码并启动应用程序时,都没有授权(这发生在第一次),我可以随后使用应用程序和API。突然我开始得到无效的凭据错误。

我使用的是client_secrets。我没有在代码的任何地方提供验证令牌,我也没有保存它。我读到可以使用刷新令牌,并且可以避免验证令牌过期。

目前,问题是我得到无效的凭据错误,我认为这是由于认证令牌过期。我不知道在这种情况下的解决方案。这是谷歌提供的示例代码,我相信它会自动处理Oauth授权(不像我们通过编程调用Oauth url,获取令牌,将其存储在某个地方并在后续请求中提供它)。我需要做些什么与样例代码,以解决这个问题,而不是在未来遇到错误?

应用程序在本地运行良好,但是当它部署在云上时,就会出现授权问题。谢谢。

复制/粘贴令牌实际上与应用程序访问Calendar API所使用的实际凭据无关;在命令行中,应用引擎SDK通过上传样例应用获得修改应用引擎项目的权限,而不管应用本身做什么。

现在,对于这里的真正问题,它实际上似乎是一个bug,其中GoogleAuthorizationCodeFlow以某种方式接收不包含refreshToken的授权代码响应,只有accessToken,然后仍然继续将其存储在数据存储中。通常情况下,你看到的流程会弹出一个页面,上面写着"这个应用程序想要:……"有离线访问"的用户在第一次加载,然后你的应用程序应该得到一个accessTokenrefreshToken对,其中accessToken通常在1小时内到期,但然后Credential对象知道如何自动捕获401异常和执行refreshToken获得一个新的accessToken,所有在引擎盖下。这可以被认为是后端服务器中返回缺乏refreshToken的凭据的错误,或者是客户端逻辑中的错误,仍然假设存在refreshToken,从而卡住而不是重新发出访问功能的请求。

幸运的是,有一个简单的解决方法。现在,您看到401错误的事实意味着在您的数据存储中,可能还有您的Memcache中存储了一个粘性的格式错误的凭据。导航到您的appengine.google.com页面,假设您还没有在那里提供一个实时的生产关键型web应用程序,转到左侧的Datastore Viewer,寻找Query -> By kind:下拉菜单,找到StoredCredential,检查所有项目,假设它们可能都来自您的日历示例,然后单击"删除"。也导航到左侧菜单上的Memcache Viewer,然后单击Flush Cache

现在,后端试图返回缺乏refreshToken的凭证的原因似乎是由于客户端试图错误地使用"自动批准"。事实证明,当我用新的JSON client_secrets创建一个全新的客户端id时,然后在加载示例日历应用程序的第一个时间,我在src/main/java/com/google/api/services/samples/calendar/appengine/server/Utils.java文件中发现了我的日志记录语句:

Credential credential = newFlow().loadCredential(userId);
if (credential.getRefreshToken() != null) {
  logger.log(Level.SEVERE, "Refresh token is not null");
} else {
  logger.log(Level.SEVERE, "Refresh token is null!");
}

那么我确实为我尝试访问它的每个唯一登录用户名获得一个refreshToken。但是,如果我从数据存储和Memcache中清除凭据,强制对后续请求进行重新身份验证,我将停止看到审批提示,并且凭据不再具有refreshtoken,从而导致它们在1小时后停止工作。

解决方案(tl;博士)

清除StoredCredential类型的所有实体的数据存储并刷新Memcache后,只需将.setApprovalPrompt("force")添加到src/main/java/com/google/api/services/samples/calendar/appengine/server/Utils.java内部的newFlow()方法中;该方法看起来像这样:

static GoogleAuthorizationCodeFlow newFlow() throws IOException {
  return new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
      getClientCredential(), Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
      DATA_STORE_FACTORY).setAccessType("offline").setApprovalPrompt("force").build();
}

可选地,在获得凭据的地方添加一些日志记录(记录实际的accessToken尤其是refreshToken通常是不好的做法,但在调试期间做一次或两次可能不会造成伤害:),并重新更新你的应用程序。你会发现第一次访问你的应用程序,你现在会得到批准提示,然后它应该永远安全工作,因为refreshToken永远不会过期,现在保存在你的数据存储中。

请注意,每个客户机/userId对发出的refreshToken数量是有限制的,如果在调试期间清除数据存储/Memcache,它会有效地泄漏一个refreshToken。行为只是在25个这样的令牌之后,较早的令牌将自动停用。有关该限制的更多信息,请参阅oauth2文档。

为了接收刷新令牌,您需要在授权请求中设置access_type=offline: https://developers.google.com/accounts/docs/OAuth2WebServer#offline

注意,您将只获得一次刷新令牌,以及第一个访问令牌。

相关内容

  • 没有找到相关文章

最新更新