【问题标题】:OAuth token expiration in MVC6 appMVC6 应用程序中的 OAuth 令牌过期
【发布时间】:2015-11-26 02:16:30
【问题描述】:

所以我有一个 MVC6 应用程序,其中包括一个身份服务器(使用 ThinkTecture 的 IdentityServer3)和一个 MVC6 Web 服务应用程序。

在 Web 服务应用程序中,我在 Startup 中使用此代码:

app.UseOAuthBearerAuthentication(options =>
{
    options.Authority = "http://localhost:6418/identity";
    options.AutomaticAuthentication = true;
    options.Audience = "http://localhost:6418/identity/resources";
});

然后我有一个控制器,其动作具有Authorize 属性。

我有一个 JavaScript 应用程序,它通过身份服务器进行身份验证,然后使用提供的 JWT 令牌访问 Web 服务操作。

这行得通,我只能使用有效令牌访问该操作。

问题出现在 JWT 过期时。我得到的是一个冗长的 ASP.NET 500 错误页面,它返回以下异常的异常信息:

System.IdentityModel.Tokens.SecurityTokenExpiredException IDX10223:生命周期验证失败。令牌已过期。

我对 OAuth 和一般的 Web API 保护还很陌生,所以我可能不太了解,但对于过期的令牌来说,500 错误似乎不适合我。这对 Web 服务客户端肯定不友好。

这是预期的行为吗?如果不是,我需要做些什么来获得更合适的响应吗?

【问题讨论】:

  • 我也遇到了同样的问题。很想知道在哪里捕获异常并返回 401。
  • 您是否仍然看到建议的修复存在此问题?

标签: oauth-2.0 asp.net-core jwt identityserver3


【解决方案1】:

编辑:此错误已在 ASP.NET Core RC2 中修复,不再需要此答案中描述的解决方法。


注意:此解决方法不适用于 ASP.NET 5 RC1due to this other bug。您可以迁移到 RC2 nightly 构建,也可以创建自定义中间件来捕获 JWT 不记名中间件抛出的异常并返回 401 响应:

app.Use(next => async context => {
    try {
        await next(context);
    }

    catch {
        // If the headers have already been sent, you can't replace the status code.
        // In this case, throw an exception to close the connection.
        if (context.Response.HasStarted) {
            throw;
        }

        context.Response.StatusCode = 401;
    }
});

遗憾的是,这就是 JWT/OAuth2 不记名中间件(由 MSFT 管理)目前默认工作的方式,但最终应该会得到修复。您可以查看此 GitHub 票证以获取更多信息:https://github.com/aspnet/Security/issues/411

幸运的是,您可以使用AuthenticationFailed 通知“轻松”解决这个问题:

app.UseOAuthBearerAuthentication(options => {
    options.Notifications = new OAuthBearerAuthenticationNotifications {
        AuthenticationFailed = notification => {
            notification.HandleResponse();

            return Task.FromResult<object>(null);
        }
    };
});

【讨论】:

  • 精确,感谢您的回答。看看这个方法,它说调用者(我假设我)必须处理完整的响应。它不知何故已经神奇地触发了 401。有没有办法以 json 的形式在正文中发送消息?
  • 虽然它通常不鼓励,是的,这是可能的。您可以/应该为此使用ApplyChallenge 通知。
  • 哦,为什么不鼓励?另外,我会同时使用两个挑战还是只使用一个?
  • 因为使用 HTTP,挑战已经在标头级别完成。 OAuth2 不记名规范为此利用了标准的 WWW-Authenticate 标头(您甚至可以设置自定义 error/error_description/error_uri:tools.ietf.org/html/rfc6750#section-3)。当然,没有什么可以阻止您在响应正文中返回消息,但这将是多余的,而且 - 显然 - 不标准。
  • 我明白了。那么我将如何为 401 设置自定义错误消息?我想这并不是真正需要的,但是能够发送用户未授权的原因会很有帮助。不是管理员,未登录,不在有效客户端上...
猜你喜欢
  • 2015-02-25
  • 2015-01-03
  • 2018-06-14
  • 2011-06-15
  • 2016-11-29
  • 2012-04-05
  • 2017-05-19
  • 2013-06-05
  • 2015-07-02
相关资源
最近更新 更多