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

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

问题描述

我是使用Google API的新手。我遵循了使用Google客户端库在eclipse中设置Google Calendar示例代码的步骤。我使用cmd命令将代码部署到应用引擎--mvn appengine:update(当试图通过eclipse进行部署时,它给了我一个错误,说该项目不是App Engine项目)。突然,在几次API请求调用之后,开始获取无效凭证错误:


错误:401

域名:全球
位置:授权
位置类型:标题

消息:凭证无效

原因:验证错误

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




  • 有些令牌我被要求粘贴在cmd上因为我正在使用命令行进行部署。之后,我可以启动我的应用程序。

  • 之后,每当我部署我的代码并启动应用程序时,就没有授权(这是第一次发生),随后我可以使用应用程序和API。 b $ b
  • 突然间,我开始出现无效凭证错误。



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



目前,问题是我得到无效的凭据错误,我相信它是因为auth令牌到期。在这种情况下,我不知道解决方案。这是谷歌提供的示例代码,我相信它会自动处理Oauth授权(与我们以编程方式调用Oauth url,获取令牌,将其存储在某处并将其提供给我们随后的请求的情况不同)。我需要怎样处理示例代码才能解决此问题,并且不会在未来出现错误?

此外,该应用程序在本地运行良好,但授权问题出现在云中时。感谢。

解决方案

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



现在,对于这里真正的问题,它实际上似乎是一个错误,其中 GoogleAuthorizationCodeFlow 以某种方式收到一个授权代码响应,其中不包含 refreshToken ,只有一个 accessToken ,然后继续将其存储在数据存储中。通常情况下,您看到的流程预计会在第一次加载时弹出一个页面,显示此应用程序想要:有离线访问权限,然后您的应用程序应该获得 accessToken refreshToken pair,其中 accessToken 通常在1小时内过期, Credential 对象知道如何自动捕获 401 异常并执行 refreshToken 来获得一个新的 accessToken ,都在后台。这可能被认为是后端服务器中缺少refreshToken的凭证的错误,或者是客户端逻辑中的错误,因为它仍然假设有一个refreshToken,因此陷入停滞状态而不是重新发出访问权限请求。 p>

幸运的是,有一个简单的解决方法。现在,您看到 401 错误的事实意味着存储在您的数据存储中并且可能还有您的Memcache中存在粘性恶意的凭据。转到您的 appengine.google.com 页面,并假设您尚未提供实时关键生产型Web应用程序,请转至数据存储查看器在左边,寻找查询 - >按照种类:下拉菜单,找到 StoredCredential ,检查所有项目,假设它们可能都来自日历示例,然后单击删除。在左侧菜单中导航到 Memcache Viewer ,然后单击刷新缓存



现在看来,后端尝试返回凭据缺少refreshToken的原因是由于客户端尝试错误地使用自动批准。事实证明这一点,当我使用新的JSON client_secrets创建一个全新的客户端ID,然后在加载示例日历应用程序的第一次时,我发现我的日志语句位于 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!);
}

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



解决方案(tl; dr)

清除您的数据存储之后, $ c> StoredCredential 并刷新你的Memcache,只需在<$ c $中添加 .setApprovalPrompt(force)到newFlow C>的src /主/ JAVA / COM /谷歌/ API /服务/样品/日历/应用服务引擎/服务器/ Utils.java ;这个方法看起来像这样:

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

$ / code>

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



请注意,每个客户端/用户ID对的RefreshTokens数量有限制,如果在调试过程中清除数据存储区/ Memcache,则会有效泄漏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天全站免登陆