6

我正在使用 ASP.Net 身份验证来控制我的应用程序授权,我需要在指定的不活动分钟后终止用户会话,我尝试通过执行以下方法来实现这一点

public void ConfigureAuth(IAppBuilder app) {
    app.CreatePerOwinContext<UserStore>(() => new UserStore());
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

    app.UseCookieAuthentication(new CookieAuthenticationOptions {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/login"),
        LogoutPath = new PathString("/logout"),
        CookieDomain = ConfigurationManager.AppSettings["CookieDomain"],
        Provider = new CookieAuthenticationProvider {
            // Enables the application to validate the security stamp when the user logs in.
            // This is a security feature which is used when you change a password or add an external login to your account.  
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(2),
                regenerateIdentity: (manager, user) => manager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie)
            )
        },
        SlidingExpiration = true,
    });
}

我也尝试过这种方法

app.UseCookieAuthentication(new CookieAuthenticationOptions {
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/login"),
    LogoutPath = new PathString("/logout"),
    CookieDomain = ConfigurationManager.AppSettings["CookieDomain"],
    ExpireTimeSpan = TimeSpan.FromMinutes(2),
    SlidingExpiration = true,
});

无论用户是否在站点中处于活动状态,使用这些 aproches 用户 cookie 会话都会在 2 分钟后过期。我在文档中读到,通过设置 SlidingExpiration = truecookie 将在 ExpireTimeSpan 中途的任何请求上重新发出。例如,如果用户登录并在 16 分钟后发出第二个请求,则 cookie 将在 30 分钟后重新发出。如果用户登录并在 31 分钟后发出第二次请求,则会提示用户登录。

我不知道为什么它不起作用,有什么想法吗?

4

2 回答 2

2

需要明确的是:CookieHandler 正在检查直到 cookie 到期的剩余时间是否小于自发出后经过的时间(意味着它已超过一半过期),然后再请求刷新。这是在 Microsoft.AspNetCore.Authentication.Cookies 的 dll 中。

就个人而言,我更希望有一个选项来更改经过的百分比。当您为更安全的应用程序使用非常小的超时(15 分钟或更短)时,让用户在仅 7 分钟不活动后超时,因为 cookie 在它们处于活动状态的前 6 分钟内从未刷新,这非常烦人。
也许添加一个选项来使用剩余时间跨度检查来代替常量。例如,当 cookie 剩余的时间少于 {TimeSpan} 时发出刷新请求。

private void CheckForRefresh(AuthenticationTicket ticket)
{
  DateTimeOffset utcNow = this.get_Clock().get_UtcNow();
  DateTimeOffset? issuedUtc = ticket.get_Properties().get_IssuedUtc();
  DateTimeOffset? expiresUtc = ticket.get_Properties().get_ExpiresUtc();
  bool? allowRefresh = ticket.get_Properties().get_AllowRefresh();
  bool flag = !allowRefresh.HasValue || allowRefresh.GetValueOrDefault();
  if (((!issuedUtc.HasValue || !expiresUtc.HasValue ? 0 : (this.get_Options().SlidingExpiration ? 1 : 0)) & (flag ? 1 : 0)) == 0)
    return;
  TimeSpan timeSpan = utcNow.Subtract(issuedUtc.Value);
  if (!(expiresUtc.Value.Subtract(utcNow) < timeSpan))
    return;
  this.RequestRefresh(ticket);
}
于 2018-12-06T15:44:28.753 回答
1

我怀疑问题在于,尽管 SlidingExpiration 为真,但刷新行为被抑制了。查看 Katana 源代码,CookieAuthenticationHandler 类,AuthenticateCoreAsync() 方法,我们看到:

bool? allowRefresh = ticket.Properties.AllowRefresh;
if (issuedUtc != null && expiresUtc != null && Options.SlidingExpiration
    && (!allowRefresh.HasValue || allowRefresh.Value))
{
    TimeSpan timeElapsed = currentUtc.Subtract(issuedUtc.Value);
    TimeSpan timeRemaining = expiresUtc.Value.Subtract(currentUtc);

    if (timeRemaining < timeElapsed)
    {
    _shouldRenew = true;
    _renewIssuedUtc = currentUtc;
    TimeSpan timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value);
    _renewExpiresUtc = currentUtc.Add(timeSpan);
    }
}

即仅当ticket.Properties.AllowRefresh 为null 或true 时才会发生刷新,并且根据您使用的中间件,它可能设置为false。例如在 OpenIdConnectAuthenticationHandler 和 WsFederationAuthenticationHandler 我们有这个......

private ClaimsPrincipal ValidateToken(...)
{
    ...
    if (Options.UseTokenLifetime)
    {
        // Override any session persistence to match the token lifetime.
        DateTime issued = jwt.ValidFrom;
        if (issued != DateTime.MinValue)
        {
            properties.IssuedUtc = issued.ToUniversalTime();
        }
        DateTime expires = jwt.ValidTo;
        if (expires != DateTime.MinValue)
        {
            properties.ExpiresUtc = expires.ToUniversalTime();
        }
        properties.AllowRefresh = false;
    }
}

注意 UseTokenLifetime 默认为 true。因此默认行为是使用我们从 IdP 服务器获得的身份验证令牌的到期时间,并在达到该到期时间时结束会话,无论用户是否处于活动状态。

于 2020-06-17T09:18:24.947 回答