ExpireTimeSpan ignorado después de regenerateIdentity / validateInterval duration en MVC Identity (2.0.1)

Me he estado rascando la cabeza todo el día en este caso. Estoy intentando configurar sesiones de inicio de sesión “muy largas” en MVC Identity 2.0.1. (30 dias).

Utilizo el siguiente inicio de cookie:

app.UseCookieAuthentication(new CookieAuthenticationOptions { SlidingExpiration = true, ExpireTimeSpan = System.TimeSpan.FromDays(30), AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/My/Login"), CookieName = "MyLoginCookie", Provider = new CookieAuthenticationProvider { OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) } }); 

Que en general, funciona bien. La cookie se establece dentro de 30 días, todo se ve bien.

Si cierro el navegador y vuelvo después de que haya pasado la duración de “validateInterval” (30 minutos aquí), aún estoy conectado, sin embargo, ahora la cookie se vuelve a emitir como “sesión” (¡el nombre correcto de la cookie sigue apareciendo)! La expiración de 30 días se ha ido.

Si cierro el navegador / vuelvo a abrir, ya no estoy conectado.

He probado eliminar el “Proveedor” y todo funciona como se esperaba, entonces, puedo volver varias horas más tarde y todavía estoy conectado correctamente. Leí que es una buena práctica usar la revalidación de sellos, así que no estoy seguro de cómo proceder.

    Cuando SecurityStampValidator desencadena la callback regenerateIdentity , el usuario autenticado se vuelve a iniciar sesión con un inicio de sesión no persistente . Esto está codificado, y no creo que haya ninguna forma de controlarlo directamente. Como tal, la sesión de inicio de sesión continuará solo hasta el final de la sesión del navegador que está ejecutando en el punto donde se regeneró la identidad.

    Aquí hay un enfoque para hacer que el inicio de sesión sea persistente, incluso en operaciones de regeneración de identidad. Esta descripción se basa en el uso de plantillas de proyectos web de Visual Studio MVC ASP.NET.

    Primero, debemos tener una forma de rastrear el hecho de que una sesión de inicio de sesión es persistente en distintas solicitudes HTTP. Esto se puede hacer agregando un reclamo “IsPersistent” a la identidad del usuario. Los siguientes métodos de extensión muestran una forma de hacerlo.

     public static class ClaimsIdentityExtensions { private const string PersistentLoginClaimType = "PersistentLogin"; public static bool GetIsPersistent(this System.Security.Claims.ClaimsIdentity identity) { return identity.Claims.FirstOrDefault(c => c.Type == PersistentLoginClaimType) != null; } public static void SetIsPersistent(this System.Security.Claims.ClaimsIdentity identity, bool isPersistent) { var claim = identity.Claims.FirstOrDefault(c => c.Type == PersistentLoginClaimType); if (isPersistent) { if (claim == null) { identity.AddClaim(new System.Security.Claims.Claim(PersistentLoginClaimType, Boolean.TrueString)); } } else if (claim != null) { identity.RemoveClaim(claim); } } } 

    A continuación, debemos hacer el reclamo “IsPersistent” cuando el usuario inicia sesión solicitando una sesión persistente. Por ejemplo, su clase ApplicationUser puede tener un método GenerateUserIdentityAsync que se puede actualizar para tomar un parámetro de indicador isPersistent siguiente manera para realizar dicho reclamo cuando sea necesario:

     public async Task GenerateUserIdentityAsync(UserManager manager, bool isPersistent) { var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); userIdentity.SetIsPersistent(isPersistent); return userIdentity; } 

    Cualquiera que llame a ApplicationUser.GenerateUserIdentityAsync ahora tendrá que pasar el indicador isPersistent . Por ejemplo, la llamada a GenerateUserIdentityAsync en AccountController.SignInAsync cambiaría de

     AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, await user.GenerateUserIdentityAsync(UserManager)); 

    a

     AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, await user.GenerateUserIdentityAsync(UserManager, isPersistent)); 

    Por último, el delegado CookieAuthenticationProvider.OnValidateIdentity utilizado en el método Startup.ConfigureAuth necesita cierta atención para conservar los detalles de persistencia en las operaciones de regeneración de identidad. El delegado predeterminado se ve así:

     OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( validateInterval: TimeSpan.FromMinutes(20), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) 

    Esto puede ser cambiado a:

     OnValidateIdentity = async (context) => { await SecurityStampValidator.OnValidateIdentity( validateInterval: TimeSpan.FromMinutes(20), // Note that if identity is regenerated in the same HTTP request as a logoff attempt, // the logoff attempt will have no effect and the user will remain logged in. // See https://aspnetidentity.codeplex.com/workitem/1962 regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager, context.Identity.GetIsPersistent()) )(context); // If identity was regenerated by the stamp validator, // AuthenticationResponseGrant.Properties.IsPersistent will default to false, leading // to a non-persistent login session. If the validated identity made a claim of being // persistent, set the IsPersistent flag to true so the application cookie won't expire // at the end of the browser session. var newResponseGrant = context.OwinContext.Authentication.AuthenticationResponseGrant; if (newResponseGrant != null) { newResponseGrant.Properties.IsPersistent = context.Identity.GetIsPersistent(); } } 

    Este error está solucionado en ASP.NET Identity 2.2. Ver https://aspnetidentity.codeplex.com/workitem/2319