我正在使用已安装的应用程序客户端ID进行Google Oauth设置。在使用GoogleWebAuthorizationBroker.AuthorizationAsync成功进行用户身份验证后,我收到了来自谷歌的访问令牌,可以按预期使用谷歌API。大约1小时后,如果我需要访问Google API,我将使用[credential.RefreshTokenAsync]函数刷新访问令牌。即使使用了刷新令牌,我也能够按预期访问Google API。
但在随机情况下,我在刷新令牌时收到以下异常。我可以确认客户端ID没有问题,因为我的客户端ID是从永久的文本文件中读取的。
更新:添加代码和更多详细信息。
由于Google API对我的应用场景的限制,我设计了如下应用程序:
- 用户将从Windows表单应用程序设置他们的Google帐户。(我在下面提到了"第一次身份验证码"(
- 我将在另一个应用程序中使用步骤1中从谷歌收到的令牌响应,该应用程序使用相同的客户端ID/机密(我在下面提到的"问题场景"代码(。因此,Google API将查看令牌响应是否已经可用,如果可用,则不会显示auth页面并检查令牌是否过期。如果已过期,我将使用RefreshTokenAsync刷新令牌
代码:
//First time authentication
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId,
ClientSecret,
},
scopes,
GoogleAuthUser,
CancellationToken.None, new FileDataStore(filepath, true)).Result;
var oauthSerivce = new Google.Apis.Oauth2.v2.Oauth2Service(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Appname",
});
//Issue scenario:
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId,
ClientSecret,
},
Scopes,
"user",
CancellationToken.None,
new FileDataStore(filepath, true)).Result;
if (credential.Token.IsExpired(credential.Flow.Clock))
{
if (credential.RefreshTokenAsync(CancellationToken.None).Result)
{
}
else
{
}
}
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
异常详细信息:
(Inner Exception #0) Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"invalid_request", Description:"Could not determine client ID from request.", Uri:""
at Google.Apis.Auth.OAuth2.Responses.TokenResponse.<FromHttpResponseAsync>d__36.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.Requests.TokenRequestExtenstions.<ExecuteAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.<FetchTokenAsync>d__35.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.<FetchTokenAsync>d__35.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.<RefreshTokenAsync>d__31.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.UserCredential.<RefreshTokenAsync>d__22.MoveNext()<---
用户将从Windows表单应用程序设置他们的Google帐户。(我在下面提到的"第一次认证码"(
实际上,除非您决定创建自己的IDatastore实现,否则您根本看不到授权代码,而自从使用fileDatastore以来,您似乎没有这样做。您尚未在您的收件箱中的任何位置指导授权代码。
我将在另一个应用程序中使用步骤1中从谷歌收到的令牌响应,该应用程序使用相同的客户端ID/机密(我在下面提到的"问题场景"代码(。因此,Google API将查看令牌响应是否已经可用,如果可用,则不会显示auth页面并检查令牌是否过期。如果已过期,我将使用RefreshTokenAsync刷新令牌。
实际上,GoogleWebAuthorizationBroker通过检查由您传递的用户表示的fileDataStore存储凭据的目录来处理所有这些。您的代码公然不做您认为正在做的事情。
发布一个混合用户和混淆文件数据存储的问题
我发现您的代码有两个问题。第一个是你在混合用户。在下面的代码中,您将为一个名为GoogleAuthUser
的用户存储用户信任钉。
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId,
ClientSecret,
},
scopes,
GoogleAuthUser,
CancellationToken.None, new FileDataStore(filepath, true)).Result;
在下面的代码中,您正在为一个名为user
的用户存储/读取redtinals
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId,
ClientSecret,
},
Scopes,
"user",
CancellationToken.None,
new FileDataStore(filepath, true)).Result;
FileDataStore将用户的credentials存储在您机器上的%appdata%中,用户由您发送的字符串表示。如果你在两个不同的调用上混合字符串,那么它将无法对用户进行身份验证。有关更多信息,请参阅FileDatastore Demistified
第二期紧急
客户端库被设计为在凭证对象加载到服务中后通过凭证对象处理授权,您不需要再关心它了。让库在什么时候是刷新访问令牌的最佳时间
if (credential.Token.IsExpired(credential.Flow.Clock))
{
if (credential.RefreshTokenAsync(CancellationToken.None).Result)
{
}
else
{
}
}
问题三
这到底是为了什么?
var oauthSerivce = new Google.Apis.Oauth2.v2.Oauth2Service(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Appname",
});