Asp.net mvc TokenResponseException-错误:";无效的“授权”;,说明:“&引用;,Uri:“&引用;

Asp.net mvc TokenResponseException-错误:";无效的“授权”;,说明:“&引用;,Uri:“&引用;,asp.net-mvc,google-api,google-oauth,Asp.net Mvc,Google Api,Google Oauth,我有一些代码可以工作——MVC应用程序使用谷歌日历API和Gmail API,并通过谷歌的OAuth2认证。代码是有效的。加载页面时,将显示来自两个服务的数据。我有一个Javascript定时器,以一定的间隔(20分钟)刷新数据。因此,在某个时间点(我猜是在某个时间间隔之后)它开始抛出异常之前,一切都按预期工作:错误:“无效的授权”,描述:,Uri:。该异常没有InnerException,只有该错误消息和StackTrace中的此信息(屏幕截图上的此处): 如果有人知道错误的原因,我会非常感

我有一些代码可以工作——MVC应用程序使用谷歌日历API和Gmail API,并通过谷歌的OAuth2认证。代码是有效的。加载页面时,将显示来自两个服务的数据。我有一个Javascript定时器,以一定的间隔(20分钟)刷新数据。因此,在某个时间点(我猜是在某个时间间隔之后)它开始抛出异常之前,一切都按预期工作:错误:“无效的授权”,描述:,Uri:。该异常没有InnerException,只有该错误消息和StackTrace中的此信息(屏幕截图上的此处):

如果有人知道错误的原因,我会非常感激。堆栈跟踪消息中的“c:\code\google.com…”行是什么,我的磁盘上没有“c:\code”文件夹。我发现了一些与相同错误相关的帖子,但不幸的是,它们没有帮助我理解这个问题。也许有更多的细节,比如这个截图,有人会有更多关于这个主题的信息。非常感谢


我发现,AppPool回收临时解决了这个问题。但是,过了一段时间,它又回来了。它与AppPool回收有什么关系

好吧,经过更多的阅读,我找到了这个异常的原因

无效授权:已超过刷新令牌限制(默认值为25)。 就这些

根据这些文件:目前每个谷歌用户帐户有25个令牌限制。如果用户帐户有25个有效令牌,则下一个身份验证请求将成功,但会在没有任何用户可见警告的情况下悄悄地使最早的未完成令牌无效

如果应用程序尝试使用无效的刷新令牌,将返回无效的\u grant错误响应。OAuth 2.0客户端和Google Analytics帐户的每一对唯一令牌的限制为25个刷新令牌(请注意,此限制可能会更改)

明白了,他们将刷新令牌的数量限制在25个,但是他们没有说明当你需要超过这个限制时该怎么做。啊。。。我一直在试验,并找到了一个解决方案,如何绕过这一限制。似乎回收应用程序池确实解决了问题(当然,直到达到下一个25个限制)。我们可以从IIS手动回收AppPool,也可以运行以下命令:

c:\Windows\System32\inetsrv\appcmd.exe recycle apppool /apppool.name:AppPoolName
您可以将该命令安排为每晚或每小时执行,无论什么

但我发现了一个解决方案:

覆盖控制器的OneException方法(适用于MVC应用程序)

其中RecycleAppool的定义如下(此操作很快,不像重新启动IIS:):

因此,在无效的_grant异常的情况下,异常“被吞没”:记录,apppool被回收,刷新令牌的限制被重置。希望这有帮助


如果您发现一些问题,请告诉我。

也可能是服务器时钟不同步。出于某种原因,我的手机无法与互联网时钟同步,而且运行速度快了6分钟。将其重置为正确的工作时间。

这正是适合我的。我与NTP同步,然后重新启动IIS。
protected override void OnException(ExceptionContext filterContext)
{
    if (filterContext.ExceptionHandled) return;

    // Log exception details
    Global.LogException(filterContext.Exception, EventLogEntryType.Error);

    if (filterContext.Exception.Message.Contains("invalid_grant"))
    {
        // Invalid Grant: The refresh token limit has been exceeded (default is 25).
        // https://developers.google.com/accounts/docs/OAuth2#expiration
        // https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtAuthorization?#helpme

        Global.RecycleAppPool();
        Global.LogException(new Exception("AppPool has been recycled"), EventLogEntryType.Information);
        Response.Redirect("Index");
    }

    var actionName = filterContext.RouteData.Values["action"].ToString();

    // Return friendly error message
    var errorMessage = string.Format("Action {0} failed with error: {1}. Please try again.", actionName, filterContext.Exception.Message);
    filterContext.Result = Content(errorMessage);

    filterContext.ExceptionHandled = true;
    base.OnException(filterContext);
}
public static void RecycleAppPool()
{
    ServerManager serverManager = new ServerManager();
    ApplicationPool appPool = serverManager.ApplicationPools["Homepage"];
    if (appPool != null)
    {
        if (appPool.State == ObjectState.Stopped) appPool.Start();
        else appPool.Recycle();
    }
}