User logout after non-persistent login in Asp.Net

2019-06-09 17:03发布

问题:

I am trying to configure Asp.Net Identity 2.2 to be able to login normally and permanently. I know there are two settings to get into account, the validateInterval of the CookieAuthenticationProvider and the ExpireTimeSpan of the CookieAuthenticationOptions. Here is the standard configuration which comes with a new MVC 5 application, with the ExpireTimeSpan and SlidingExpiration set explicitly to their default values just to have them in mind:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    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(30),
            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    },
    ExpireTimeSpan = TimeSpan.FromDays(14),
    SlidingExpiration = true,
});

OnValidateIdentity is called every 30 minutes and checks the security stamp of the user. If it hasn't been changed (so e.g. the user has not changed his password), nothing happens - the user remains logged in. Which is OK.

If I login normally (not-persistent) a cookie is created with expiration "on browser close". Thus the time of logout is not controlled in any way and the user remains logged in until he/she closes the browser or makes a change which invalidates the security stamp (change password or email, etc.).

If I login persistently the same cookie is created but it has expiration in 14 days (which is how persistent login usually works, it is not "forever" but for some time only). So the user remains logged in as long as he/she uses the application at least once every 14 days.

My question is: how can I make the normal (non-persistent) login to expire after some time, e.g. 15 minutes, even if the user does not close the browser and the security stamp remains unchanged (which is equivalent of leaving the browser open for 15 minutes)? If I set ExpireTimeSpan to 15 minutes all sessions (including persistent) become 15 minutes only which is not a solution.

回答1:

I succeeded to achieve this by inheriting from SignInManager, adding a new property:

/// <summary>
///     Defines how long a user session lasts if it is non persistent. A null value means until the browser is closed (default)
/// </summary>
public virtual TimeSpan? NonPersistentSessionDuration { get; set; }

and overriding the method:

/// <summary>
/// Creates a user identity and then signs the identity using the AuthenticationManager
/// </summary>
/// <param name="user"></param>
/// <param name="isPersistent"></param>
/// <param name="rememberBrowser"></param>
/// <returns></returns>
public virtual async Task SignInAsync(TUser user, bool isPersistent, bool rememberBrowser)
{
    var userIdentity = await CreateUserIdentityAsync(user).WithCurrentCulture();
    // Clear any partial cookies from external or two factor partial sign ins
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie, DefaultAuthenticationTypes.TwoFactorCookie);

    var properties = new AuthenticationProperties {IsPersistent = isPersistent};
    if (!isPersistent && this.NonPersistentSessionDuration != null)
        properties.ExpiresUtc = DateTimeOffset.UtcNow.Add(this.NonPersistentSessionDuration.Value);
    if (rememberBrowser)
    {
        var rememberBrowserIdentity = AuthenticationManager.CreateTwoFactorRememberBrowserIdentity(ConvertIdToString(user.Id));
        AuthenticationManager.SignIn(properties, userIdentity, rememberBrowserIdentity);
    }
    else
    {
        AuthenticationManager.SignIn(properties, userIdentity);
    }
}

The change is setting the ExpiresUtc property of the AuthenticationProperties object for non-persistent sign in.

Of course in the SignInManager configuration you have to set the new NonPersistentSessionDuration property to some value which will be the session length for non-persistent sessions.