凭据无效:Google API日历

时间:2014-08-19 17:57:10

标签: google-app-engine oauth google-api google-calendar-api google-api-java-client

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

突然,在几次API请求调用之后,开始收到无效的凭据错误:

  

错误:401个
  域名:全球
  地点:授权
  locationtype:header
  消息:凭证无效
  原因:验证错误

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

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

我使用的是从开发人员控制台生成的client_secrets.json,我没有在代码中的任何地方提供auth令牌,我也没有保存它。我读到可以使用刷新令牌,这可以避免身份验证令牌过期。

目前,问题是我收到了无效的凭据错误,我认为这是因为auth令牌过期。在这种情况下,我不知道解决方案。这是Google提供的示例代码,我相信它会自动处理Oauth授权(与我们以编程方式调用Oauth网址,获取令牌,将其存储在某处并为其提供后续请求的情况不同)。我需要对示例代码做什么才能解决此问题而不是将来遇到错误?

此外,应用程序在本地运行正常,但在云上部署时会出现授权问题。感谢。

2 个答案:

答案 0 :(得分:2)

复制/粘贴令牌实际上与应用程序用于访问Calendar API的实际凭据无关;在命令行上,App Engine SDK获得了通过上传示例应用程序修改App Engine项目的权限,无论应用程序本身做什么。

现在,对于这里的实际问题,它实际上似乎是一个错误,GoogleAuthorizationCodeFlow以某种方式接收到授权代码响应,该响应不包含refreshToken,只有{{1}然后仍然继续将其存储在数据存储区中。通常情况下,您看到的流程会弹出一个页面,上面写着"此应用程序希望:...具有离线访问权限"对于第一次加载的用户,然后您的应用应该获得accessTokenaccessToken对,其中refreshToken通常在1小时内到期,然后是accessToken对象知道如何自动捕获Credential异常并执行401以获得新的refreshToken,所有这些都在幕后。这可能被认为是后端服务器中的一个错误,用于返回缺少refreshToken的凭证,或者客户端逻辑中的错误,因为仍然假设有一个刷新,因此卡住而不是重新发出访问权限请求

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

现在,看起来后端尝试返回缺少refreshToken的凭据的原因是由于客户端试图错误地使用"自动批准"。事实证明,当我使用新的JSON client_secrets创建一个全新的客户端ID时,然后在第一次时间加载示例日历应用程序时,我发现我的日志记录语句在Flush Cache档案:

src/main/java/com/google/api/services/samples/calendar/appengine/server/Utils.java

然后我为每个尝试访问它的唯一登录用户名获取一个refreshToken。但是,如果我从数据存储区和内存缓存中清除凭据,强制对后续请求进行重新验证,我将停止查看批准提示,并且我的凭据将停止使用refreshTokens,从而导致它们在1小时后停止工作。

解决方案(tl; dr)

清除所有实体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!"); } 的数据存储区并刷新Memcache后,只需将StoredCredential添加到.setApprovalPrompt("force")内的newFlow()方法中;该方法将如下所示:

src/main/java/com/google/api/services/samples/calendar/appengine/server/Utils.java

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

请注意,每个client / userId对发出的refreshTokens数量有限制,如果在调试期间清除数据存储/ Memcache,则会有效地泄漏refreshToken。行为只是在25个这样的令牌之后,之前的那些将自动被停用。有关该限制的详细信息,请参阅oauth2 docs

答案 1 :(得分:1)

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

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