凭据无效:Google API 日历 [英] Invalid credentials: Google API calendar

查看:25
本文介绍了凭据无效:Google API 日历的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

<块引用>

错误:401
域:全球
地点:授权
位置类型:标题
消息:凭据无效
原因:身份验证错误

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

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

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

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

此外,该应用程序在本地运行良好,但在部署到云上时出现授权问题.谢谢.

解决方案

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

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

幸运的是,有一个简单的解决方法.现在,您看到 401 错误这一事实意味着您的数据存储区以及可能还有 Memcache 中存储了格式错误的粘性凭证.导航到您的 appengine.google.com 页面,假设您尚未在那里提供实时生产关键型 Web 应用程序,请转到左侧的 Datastore Viewer,查看对于 Query ->按种类: 下拉菜单,找到 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);如果 (credential.getRefreshToken() != null) {logger.log(Level.SEVERE, "刷新令牌不为空");} 别的 {logger.log(Level.SEVERE, "刷新令牌为空!");}

然后我会为我尝试访问它的每个唯一登录用户名获得一个 refreshToken.但是,如果我从 Datastore 和 Memcache 中清除凭据,强制对后续请求进行重新身份验证,我将不再看到批准提示,我的凭据也不再具有 refreshTokens,从而导致它们在 1 小时后停止工作.

解决方案(tl;dr)

在为 StoredCredential 类型的所有实体清除数据存储区并刷新 Memcache 后,只需将 .setApprovalPrompt("force") 添加到 .setApprovalPrompt("force").setApprovalPrompt("force")代码>src/main/java/com/google/api/services/samples/calendar/appengine/server/Utils.java;该方法将如下所示:

静态 GoogleAuthorizationCodeFlow newFlow() 抛出 IOException {返回新的 GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,getClientCredential(), Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(DATA_STORE_FACTORY).setAccessType("offline").setApprovalPrompt("force").build();}

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

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

I am new to using Google APIs. I followed steps to setup Google Calendar sample code in eclipse using Google client library. I deployed the code to app engine using the cmd command- mvn appengine:update (when tried to deploy through eclipse it gave me an error saying the project is not an App Engine project). Deploying through command line worked and I could launch my web application.

Suddenly, after few API request calls, started getting invalid credentials error:

error:401
domain:global
location: authorization
locationtype : header
message: invalid credentials
reason: auth error

I searched this error and found it may occur if your auth token is invalid or expired. I am not sure what I need to do to get a new auth token. In my case, there is a client_secrets.json file which has the client secrets. I did not put/save or use the auth token anywhere in the code. Following is what I remember when I deployed the code for the first time:

  • There was some token which I was asked to paste on the cmd as I was deploying using the command line. After that I could launch my application.
  • After that whenever I deployed my code and launched the application, there was no authorization(which happened the first time) and I could use the application and the API subsequently.
  • Suddenly I started getting invalid credentials error.

I was using client_secrets.json generated from the developer's console and I did not provide auth token anywhere in the code and I did not save it either. I read that a refresh token can be used and that can avoid expiration of the auth token.

Currently, the issue is that I am getting invalid credentials error and I believe it is because of expiration of auth token. I am not aware about the solution in this case. It is the sample code provided by Google and I believe it automatically handles Oauth authorization (unlike the case where we programmatically call an Oauth url, get a token, store it somewhere and provide it with our subsequent requests). What do I need to do with the sample code so as to resolve this and not to run into the error in future?

Also that the application is running fine locally, but the authorization issue comes when it is deployed on the cloud. Thanks.

解决方案

The copy/paste token was actually unrelated to the actual credentials being used by the app for accessing the Calendar API; on the command line, it was the App Engine SDK getting permission to modify your App Engine project by uploading the sample app, regardless of what the app itself does.

Now, for the real issue here, it actually seems to be a bug where the GoogleAuthorizationCodeFlow somehow receives an authorization code response which doesn't contain a refreshToken, only an accessToken, and then still goes on to store it in Datastore. Normally, the flow you see is expected to pop up a page saying "This app would like to: ... Have offline access" for the user on the first load, and then your app is supposed to get an accessToken and refreshToken pair, where the accessToken typically expires within 1 hour but then the Credential object knows how to automatically catch the 401 exception and execute the refreshToken to get a new accessToken, all under the hood. This could either be considered a bug in the backend server for returning a credential which lacks a refreshToken, or a bug in the client logic for still assuming there's a refreshToken and thus getting stuck rather than re-issuing a request for access capabilities.

Fortunately, there's an easy workaround. Right now, the fact that you're seeing the 401 error means there's a sticky malformed credential stored in your Datastore and possibly also your Memcache. Navigate to your appengine.google.com page, and assuming you aren't already serving a live production-critical web application there, go to Datastore Viewer on the left, look for the Query -> By kind: drop-down menu, to find StoredCredential, check all the items assuming they likely all came from your Calendar sample, and click "Delete". Also navigate to Memcache Viewer on the left-hand-side menu, and then click Flush Cache.

Now, it appears the reason the backends are trying to return credentials lacking a refreshToken is due to the client trying to incorrectly make use of "auto-approval". This is evidenced by the fact that when I create a brand-new client id with a new JSON client_secrets, then on just the very first time loading the sample calendar app, I find with my logging statements inside the src/main/java/com/google/api/services/samples/calendar/appengine/server/Utils.java file:

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!");
}

then I do get a refreshToken for each unique login username I try to access it with. However, if I purge the credential from Datastore and Memcache, forcing a re-authentication on a subsequent request, I stop seeing the approval prompt and my credentials stop having refreshTokens, thus causing them to stop working 1 hour later.

Solution (tl;dr)

After purging your Datastore for all entities of kind StoredCredential and flushing your Memcache, simply add .setApprovalPrompt("force") to the newFlow() method inside of src/main/java/com/google/api/services/samples/calendar/appengine/server/Utils.java; the method will look like this:

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();
}

Optionally, add some logging where the credential is obtained (it's generally bad practice to log the actual accessToken and especially the refreshToken, but during debugging doing it once or twice probably doesn't hurt :), and re-update your app. You'll find that the first time you access your app, you'll get the approval prompt now, and then it should safely work forever since the refreshToken never expires and is now saved in your Datastore.

Note that there's a limit on the number of refreshTokens per client/userId pair ever issued, and if you do purge your Datastore/Memcache during debugging, it effectively leaks a refreshToken. The behavior is just that after 25 such tokens, the earlier ones will automatically be deactivated. See the oauth2 docs for more info on that limit.

这篇关于凭据无效:Google API 日历的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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