如何在 Razor 页面中获取 ASP.NET 身份验证票过期?

How to get ASP.NET Identity authentication ticket expiry in Razor Page?

我将 identityserver4 与 ASP.NET 身份一起使用,cookie 配置为 SlidingExpiration = true 和 ExpireTimeSpan = 20 分钟。我想在用户即将超时时向用户发出警告,因此我尝试访问 cookie 中的“.expiry”值。

到目前为止,我已经能够使用下面的 Razor 代码读取 an 到期时间。 但是当用户刷新他们的票时,这无法读取正确的到期时间。根据 Microsoft docs SlidingExpiration,如果他们在获得票证后刷新页面 10 分钟或更长时间(>= ExpireTimeSpan 的 50%),则应该为我的用户提供新票证。它做得很好,但是当它这样做时,下面的代码会提供旧的到期时间,直到用户第二次刷新页面!

@(DateTime.Parse(((await Context.AuthenticateAsync()).Properties.Items)[".expires"]))

我想知道的是如何在提供新票时生成的页面上获得正确的到期时间?

这里的问题是更新是在您的页面呈现后发生的 - 新属性将仅在后续请求中可用。

一个选项可能是使用客户端代码来轮询最新的到期时间,但这会产生 keep-alive 的效果,这可能不是您想要的。

为了缓解上述问题,您可以创建自己的 cookie 中间件实现(所有源代码都在 github 上)并自定义滑动过期逻辑(CheckForRefresh 和 RequestRefresh)。您还可以将新的到期时间添加到 HttpContext 中,从而使它更早地可用于您的控制器代码。

源代码:https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.Cookies

您只需要创建您自己的 CookieAuthenticationHandler 版本(少于 500 行代码)和您自己的注册助手(查看 CookieExtensions):

public static AuthenticationBuilder AddCustomCookie(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<CookieAuthenticationOptions> configureOptions)
{
    builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptions>());
    return builder.AddScheme<CookieAuthenticationOptions, CustomCookieAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
}

我已经解决了我的问题,我不太喜欢这个解决方案,因为它太老套了。它确实有效,所以我将其张贴在这里以防它有帮助。如果有人能帮助我理解更好的解决方案,我将不胜感激,我将编辑此答案或将其删除以支持发生的另一个 if/when。

我以与我的问题大致相同的方式获得身份验证票过期,然后如果我的 ExpireTimeSpan 设置还剩不到 50%,我认为它会更新(可能有点冒险,但到目前为止它是最好的我已经管理)。我用它来计算超时前剩余的假设秒数,然后在决定何时向用户显示警告时使用这个值。

剃刀顶部(部分):

@using Microsoft.AspNetCore.Authentication;

我的代码的重要部分(随时提出改进建议):

secondsRemaining = "@(DateTime.Parse(((await AuthenticationHttpContextExtensions
                                             .AuthenticateAsync(Context))
                                             .Properties
                                             .Items)[".expires"])
                     .Subtract(DateTime.Now)
                     .TotalSeconds)";
// If secondsRemaining is less than half the expiry timespan then assume it will be re-issued
if (secondsRemaining < timeoutSeconds / 2) {
    secondsRemaining = timeoutSeconds;
}