我是使用Google API的新手。我按照步骤使用Google客户端库在eclipse中设置Google Calendar示例代码。我使用cmd命令-mvn appengine:update将代码部署到app引擎(当试图通过eclipse部署时,它给了我一个错误,说项目不是App Engine项目)。通过命令行部署工作,我可以启动我的Web应用程序。
突然,在几次API请求调用之后,开始收到无效的凭据错误:
错误:401个
域名:全球
地点:授权
locationtype:header
消息:凭证无效
原因:验证错误
我搜索了此错误,发现如果您的身份验证令牌无效或已过期,可能会发生此错误。我不确定我需要做什么才能获得新的身份验证令牌。在我的例子中,有一个client_secrets.json文件,它有客户机密码。我没有在代码中的任何地方放置/保存或使用身份验证令牌。以下是我第一次部署代码时的记忆:
我使用的是从开发人员控制台生成的client_secrets.json,我没有在代码中的任何地方提供auth令牌,我也没有保存它。我读到可以使用刷新令牌,这可以避免身份验证令牌过期。
目前,问题是我收到了无效的凭据错误,我认为这是因为auth令牌过期。在这种情况下,我不知道解决方案。这是Google提供的示例代码,我相信它会自动处理Oauth授权(与我们以编程方式调用Oauth网址,获取令牌,将其存储在某处并为其提供后续请求的情况不同)。我需要对示例代码做什么才能解决此问题而不是将来遇到错误?
此外,应用程序在本地运行正常,但在云上部署时会出现授权问题。感谢。
答案 0 :(得分:2)
复制/粘贴令牌实际上与应用程序用于访问Calendar API的实际凭据无关;在命令行上,App Engine SDK获得了通过上传示例应用程序修改App Engine项目的权限,无论应用程序本身做什么。
现在,对于这里的实际问题,它实际上似乎是一个错误,GoogleAuthorizationCodeFlow
以某种方式接收到授权代码响应,该响应不包含refreshToken
,只有{{1}然后仍然继续将其存储在数据存储区中。通常情况下,您看到的流程会弹出一个页面,上面写着"此应用程序希望:...具有离线访问权限"对于第一次加载的用户,然后您的应用应该获得accessToken
和accessToken
对,其中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
请注意,您只能获得一次刷新令牌以及第一个访问令牌。