Uso de la autenticación cookie sin Identity ASP.NET Core

Por Rick Anderson

Identity ASP.NET Core es un proveedor de autenticación completo para crear y mantener inicios de sesión. Sin embargo, se puede usar un proveedor de autenticación basado en cookie sin Identity ASP.NET Core. Para más información, vea Introducción a Identity en ASP.NET Core.

Vea o descargue el código de ejemplo (cómo descargarlo)

Con fines de demostración en la aplicación de ejemplo, la cuenta de usuario del usuario hipotético, María Rodríguez, se codifica de forma rígida en la aplicación. Use la dirección de correo electrónicomaria.rodriguez@contoso.com y cualquier contraseña para iniciar sesión en el usuario. El usuario se autentica en el método AuthenticateUser del archivo Pages/Account/Login.cshtml.cs. En un ejemplo real, el usuario se autenticaría en un almacén de datos.

using Microsoft.AspNetCore.Authentication.Cookies;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie();

builder.Services.AddHttpContextAccessor();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

AuthenticationScheme pasado a AddAuthentication establece el esquema de autenticación predeterminado para la aplicación. AuthenticationScheme resulta útil cuando hay varias instancias de autenticación cookie y la aplicación debe autorizarse con un esquema específico. Al establecer AuthenticationScheme en CookieAuthenticationDefaults.AuthenticationScheme se proporciona un valor "Cookies" para el esquema. Se puede usar cualquier valor de cadena que distinga el esquema.

El esquema de autenticación de la aplicación es diferente del esquema de autenticación cookie de la aplicación. Cuando no se proporciona un esquema de autenticación cookie en AddCookie, se usa CookieAuthenticationDefaults.AuthenticationScheme. El CookieAuthenticationDefaults.AuthenticationSchemeOrigen de GitHub muestra que está establecido en "Cookies".

La propiedad IsEssential de cookie de la autenticación se establece en true de manera predeterminada. Se permiten autenticaciones cookie cuando un visitante del sitio no ha consentido la recopilación de datos. Para obtener más información, vea Compatibilidad con el Reglamento general de protección de datos (RGPD) en ASP.NET Core.

La clase CookieAuthenticationOptions se usa para configurar las opciones del proveedor de autenticación.

Configure CookieAuthenticationOptions en el método AddCookie:

using Microsoft.AspNetCore.Authentication.Cookies;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
        options.SlidingExpiration = true;
        options.AccessDeniedPath = "/Forbidden/";
    });

builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

El Cookie middleware de directivas (origen de GitHub)UseCookiePolicy habilita las funcionalidades de directiva cookie. El middleware se procesa en el orden en que se agrega:

app.UseCookiePolicy(cookiePolicyOptions);

Use CookiePolicyOptions proporcionado en el middleware de directivas Cookie para controlar las características globales del procesamiento cookie y enlazar a los controladores de procesamiento cookie cuando se anexan o eliminan cookie.

El valor predeterminado MinimumSameSitePolicy es SameSiteMode.Lax para permitir la autenticación de OAuth2. Para aplicar estrictamente una directiva de mismo sitio de SameSiteMode.Strict, establezca MinimumSameSitePolicy. Aunque esta configuración interrumpe OAuth2 y otros esquemas de autenticación entre orígenes, eleva el nivel de seguridad cookie para otros tipos de aplicaciones que no se basan en el procesamiento de solicitudes entre orígenes.

var cookiePolicyOptions = new CookiePolicyOptions
{
    MinimumSameSitePolicy = SameSiteMode.Strict,
};

La configuración de middleware de directivas Cookie para MinimumSameSitePolicy puede afectar el valor de Cookie.SameSite en la configuración CookieAuthenticationOptions según la matriz siguiente.

MinimumSameSitePolicy Cookie.SameSite Configuración resultante Cookie.SameSite
SameSiteMode.None SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Lax SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Lax
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Strict SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Strict
SameSiteMode.Strict
SameSiteMode.Strict

Para crear una información de usuario que contiene cookie, construya un objeto ClaimsPrincipal. La información del usuario se serializa y almacena en cookie.

Cree un objeto ClaimsIdentity con los elementos Claim necesarios y llame a SignInAsync para iniciar sesión en el usuario. En la aplicación de ejemplo, Login.cshtml.cs contiene el siguiente código:

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    ReturnUrl = returnUrl;

    if (ModelState.IsValid)
    {
        // Use Input.Email and Input.Password to authenticate the user
        // with your custom authentication logic.
        //
        // For demonstration purposes, the sample validates the user
        // on the email address maria.rodriguez@contoso.com with 
        // any password that passes model validation.

        var user = await AuthenticateUser(Input.Email, Input.Password);

        if (user == null)
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }

        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, user.Email),
            new Claim("FullName", user.FullName),
            new Claim(ClaimTypes.Role, "Administrator"),
        };

        var claimsIdentity = new ClaimsIdentity(
            claims, CookieAuthenticationDefaults.AuthenticationScheme);

        var authProperties = new AuthenticationProperties
        {
            //AllowRefresh = <bool>,
            // Refreshing the authentication session should be allowed.

            //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10),
            // The time at which the authentication ticket expires. A 
            // value set here overrides the ExpireTimeSpan option of 
            // CookieAuthenticationOptions set with AddCookie.

            //IsPersistent = true,
            // Whether the authentication session is persisted across 
            // multiple requests. When used with cookies, controls
            // whether the cookie's lifetime is absolute (matching the
            // lifetime of the authentication ticket) or session-based.

            //IssuedUtc = <DateTimeOffset>,
            // The time at which the authentication ticket was issued.

            //RedirectUri = <string>
            // The full path or absolute URI to be used as an http 
            // redirect response value.
        };

        await HttpContext.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme, 
            new ClaimsPrincipal(claimsIdentity), 
            authProperties);

        _logger.LogInformation("User {Email} logged in at {Time}.", 
            user.Email, DateTime.UtcNow);

        return LocalRedirect(Url.GetLocalUrl(returnUrl));
    }

    // Something failed. Redisplay the form.
    return Page();
}

Si quiere que los comentarios de código se traduzcan en más idiomas además del inglés, háganoslo saber en este problema de debate de GitHub.

SignInAsync crea un cookie cifrado y lo agrega a la respuesta actual. Si AuthenticationScheme no se especifica, se usa el esquema predeterminado.

RedirectUri solo se usa en algunas rutas de acceso específicas de manera predeterminada, por ejemplo, la ruta de acceso de inicio de sesión y las rutas de cierre de sesión. Para obtener más información, consulte el Cookieorigen AuthenticationHandler.

Se usa el sistema de protección de datos de ASP.NET Core para el cifrado. En el caso de una aplicación hospedada en varias máquinas, el equilibrio de carga entre aplicaciones o el uso de una granja de servidores web, configure la protección de datos para usar el mismo anillo de claves y el mismo identificador de aplicación.

Cerrar sesión

Para cerrar la sesión del usuario actual y eliminar su cookie, llame a SignOutAsync:

public async Task OnGetAsync(string returnUrl = null)
{
    if (!string.IsNullOrEmpty(ErrorMessage))
    {
        ModelState.AddModelError(string.Empty, ErrorMessage);
    }

    // Clear the existing external cookie
    await HttpContext.SignOutAsync(
        CookieAuthenticationDefaults.AuthenticationScheme);

    ReturnUrl = returnUrl;
}

Si CookieAuthenticationDefaults.AuthenticationScheme o "Cookie" no se usan como esquema, proporcione el esquema usado al configurar el proveedor de autenticación. De lo contrario, se usa el esquema predeterminado. Por ejemplo, si se usa "ContosoCookie" como el esquema, proporcione el esquema usado al configurar el proveedor de autenticación.

Cuando el explorador se cierra, elimina automáticamente los cookie basados en sesión (cookie no persistentes), pero no se borran cookie cuando se cierra una pestaña individual. El servidor no recibe notificaciones de eventos de cierre de pestaña o explorador.

Reaccionar a los cambios de back-end

Una vez creado cookie, cookie es el único origen de identidad. Si una cuenta de usuario está deshabilitada en sistemas back-end:

  • El sistema de autenticación cookie de la aplicación continúa procesando solicitudes basadas en la autenticación cookie.
  • El usuario permanece conectado a la aplicación siempre que la autenticación cookie sea válida.

El evento ValidatePrincipal se puede usar para interceptar e invalidar la validación de la identidad cookie. Validar cookie en cada solicitud mitiga el riesgo de que los usuarios revocados accedan a la aplicación.

Un enfoque para la validación cookie se basa en realizar un seguimiento de cuándo cambia la base de datos de usuario. Si no se ha cambiado la base de datos desde que se emitió el cookie del usuario, no es necesario volver a autenticar al usuario si su cookie sigue siendo válido. En la aplicación de ejemplo, la base de datos se implementa en IUserRepository y almacena un valor LastChanged. Cuando un usuario se actualiza en la base de datos, el valor LastChanged se establece en la hora actual.

Para invalidar cookie cuando la base de datos cambia en función del valor LastChanged, cree cookie con una notificación LastChanged que contenga el valor actual LastChanged de la base de datos:

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, user.Email),
    new Claim("LastChanged", {Database Value})
};

var claimsIdentity = new ClaimsIdentity(
    claims,
    CookieAuthenticationDefaults.AuthenticationScheme);

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme, 
    new ClaimsPrincipal(claimsIdentity));

Para implementar una invalidación para el evento ValidatePrincipal, escriba un método con la siguiente firma en una clase que derive de CookieAuthenticationEvents:

ValidatePrincipal(CookieValidatePrincipalContext)

A continuación se muestra una implementación de ejemplo de CookieAuthenticationEvents:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;

public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
    private readonly IUserRepository _userRepository;

    public CustomCookieAuthenticationEvents(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
    {
        var userPrincipal = context.Principal;

        // Look for the LastChanged claim.
        var lastChanged = (from c in userPrincipal.Claims
                           where c.Type == "LastChanged"
                           select c.Value).FirstOrDefault();

        if (string.IsNullOrEmpty(lastChanged) ||
            !_userRepository.ValidateLastChanged(lastChanged))
        {
            context.RejectPrincipal();

            await context.HttpContext.SignOutAsync(
                CookieAuthenticationDefaults.AuthenticationScheme);
        }
    }
}

Registre la instancia de eventos durante el registro del servicio cookie. Proporcione un registro de servicio con ámbito para la clase CustomCookieAuthenticationEvents:

using Microsoft.AspNetCore.Authentication.Cookies;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.EventsType = typeof(CustomCookieAuthenticationEvents);
    });

builder.Services.AddScoped<CustomCookieAuthenticationEvents>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

Considere una situación en la que se actualiza el nombre del usuario, una decisión que no afecta a la seguridad de ninguna manera. Si desea actualizar de forma no destructiva la entidad de seguridad de usuario, llame a context.ReplacePrincipal y establezca la propiedad context.ShouldRenew en true.

Advertencia

El enfoque descrito aquí se desencadena en cada solicitud. La validación de autenticación cookie para todos los usuarios en cada solicitud puede provocar una gran penalización de rendimiento para la aplicación.

cookie persistente

Es posible que desee que cookie persista en las sesiones del explorador. Esta persistencia solo debe habilitarse con el consentimiento explícito del usuario con una casilla "Recordarme" al iniciar sesión o un mecanismo similar.

El siguiente fragmento de código crea una identidad y el cookie correspondiente que sobrevive a través de cierres del explorador. Se respetan las opciones de expiración deslizante configuradas anteriormente. Si cookie expira mientras se cierra el explorador, el explorador borra cookie una vez reiniciado.

Establezca IsPersistent en true en AuthenticationProperties:

// using Microsoft.AspNetCore.Authentication;

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity),
    new AuthenticationProperties
    {
        IsPersistent = true
    });

Se puede establecer una hora de expiración absoluta con ExpiresUtc. Para crear un objeto persistente cookie, IsPersistent también debe establecerse. De lo contrario, cookie se crea con una duración basada en sesión y podría expirar antes o después del vale de autenticación que contiene. Cuando ExpiresUtc se establece, invalida el valor de la opción ExpireTimeSpan de CookieAuthenticationOptions, si se establece.

El siguiente fragmento de código crea una identidad y el cookie correspondiente que dura 20 minutos. Esto omite cualquier configuración de expiración deslizante configurada anteriormente.

// using Microsoft.AspNetCore.Authentication;

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity),
    new AuthenticationProperties
    {
        IsPersistent = true,
        ExpiresUtc = DateTime.UtcNow.AddMinutes(20)
    });

Identity ASP.NET Core es un proveedor de autenticación completo para crear y mantener inicios de sesión. Sin embargo, se puede usar un proveedor de autenticación basado en cookie sin Identity ASP.NET Core. Para más información, vea Introducción a Identity en ASP.NET Core.

Vea o descargue el código de ejemplo (cómo descargarlo)

Con fines de demostración en la aplicación de ejemplo, la cuenta de usuario del usuario hipotético, María Rodríguez, se codifica de forma rígida en la aplicación. Use la dirección de correo electrónicomaria.rodriguez@contoso.com y cualquier contraseña para iniciar sesión en el usuario. El usuario se autentica en el método AuthenticateUser del archivo Pages/Account/Login.cshtml.cs. En un ejemplo real, el usuario se autenticaría en una base de datos.

Configuración

En el método Startup.ConfigureServices, cree los servicios de middleware de autenticación con los métodos AddAuthentication y AddCookie:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie();

AuthenticationScheme pasado a AddAuthentication establece el esquema de autenticación predeterminado para la aplicación. AuthenticationScheme resulta útil cuando hay varias instancias de autenticación cookie y desea autorizar con un esquema específico. Al establecer AuthenticationScheme en CookieAuthenticationDefaults.AuthenticationScheme se proporciona un valor "Cookies" para el esquema. Puede proporcionar cualquier valor de cadena que distinga el esquema.

El esquema de autenticación de la aplicación es diferente del esquema de autenticación cookie de la aplicación. Cuando no se proporciona un esquema de autenticación cookie en AddCookie, se usa CookieAuthenticationDefaults.AuthenticationScheme ("Cookies").

La propiedad IsEssential de cookie de la autenticación se establece en true de manera predeterminada. Se permiten autenticaciones cookie cuando un visitante del sitio no ha consentido la recopilación de datos. Para obtener más información, vea Compatibilidad con el Reglamento general de protección de datos (RGPD) en ASP.NET Core.

En Startup.Configure, llame a UseAuthentication y UseAuthorization para establecer la propiedad HttpContext.User y ejecute el middleware de autorización para las solicitudes. Llame a los métodos UseAuthentication y UseAuthorization antes de llamar a UseEndpoints:

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapRazorPages();
});

La clase CookieAuthenticationOptions se usa para configurar las opciones del proveedor de autenticación.

Establezca CookieAuthenticationOptions en la configuración del servicio para la autenticación en el método Startup.ConfigureServices:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        ...
    });

El middleware de directivas Cookie habilita las funcionalidades de directiva cookie. Agregar el middleware a la canalización de procesamiento de las aplicaciones distingue el orden; solo afecta a los componentes de bajada registrados en la canalización.

app.UseCookiePolicy(cookiePolicyOptions);

Use CookiePolicyOptions proporcionado en el middleware de directivas Cookie para controlar las características globales del procesamiento cookie y enlazar a los controladores de procesamiento cookie cuando se anexan o eliminan cookie.

El valor predeterminado MinimumSameSitePolicy es SameSiteMode.Lax para permitir la autenticación de OAuth2. Para aplicar estrictamente una directiva de mismo sitio de SameSiteMode.Strict, establezca MinimumSameSitePolicy. Aunque esta configuración interrumpe OAuth2 y otros esquemas de autenticación entre orígenes, eleva el nivel de seguridad cookie para otros tipos de aplicaciones que no se basan en el procesamiento de solicitudes entre orígenes.

var cookiePolicyOptions = new CookiePolicyOptions
{
    MinimumSameSitePolicy = SameSiteMode.Strict,
};

La configuración de middleware de directivas Cookie para MinimumSameSitePolicy puede afectar el valor de Cookie.SameSite en la configuración CookieAuthenticationOptions según la matriz siguiente.

MinimumSameSitePolicy Cookie.SameSite Configuración resultante Cookie.SameSite
SameSiteMode.None SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Lax SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Lax
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Strict SameSiteMode.None
SameSiteMode.Lax
SameSiteMode.Strict
SameSiteMode.Strict
SameSiteMode.Strict
SameSiteMode.Strict

Para crear una información de usuario que contiene cookie, construya un objeto ClaimsPrincipal. La información del usuario se serializa y almacena en cookie.

Cree un ClaimsIdentity con los Claim necesarios y llame a SignInAsync para iniciar sesión en el usuario:

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, user.Email),
    new Claim("FullName", user.FullName),
    new Claim(ClaimTypes.Role, "Administrator"),
};

var claimsIdentity = new ClaimsIdentity(
    claims, CookieAuthenticationDefaults.AuthenticationScheme);

var authProperties = new AuthenticationProperties
{
    //AllowRefresh = <bool>,
    // Refreshing the authentication session should be allowed.

    //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10),
    // The time at which the authentication ticket expires. A 
    // value set here overrides the ExpireTimeSpan option of 
    // CookieAuthenticationOptions set with AddCookie.

    //IsPersistent = true,
    // Whether the authentication session is persisted across 
    // multiple requests. When used with cookies, controls
    // whether the cookie's lifetime is absolute (matching the
    // lifetime of the authentication ticket) or session-based.

    //IssuedUtc = <DateTimeOffset>,
    // The time at which the authentication ticket was issued.

    //RedirectUri = <string>
    // The full path or absolute URI to be used as an http 
    // redirect response value.
};

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme, 
    new ClaimsPrincipal(claimsIdentity), 
    authProperties);

Si quiere que los comentarios de código se traduzcan en más idiomas además del inglés, háganoslo saber en este problema de debate de GitHub.

SignInAsync crea un cookie cifrado y lo agrega a la respuesta actual. Si AuthenticationScheme no se especifica, se usa el esquema predeterminado.

RedirectUri solo se usa en algunas rutas de acceso específicas de manera predeterminada, por ejemplo, la ruta de acceso de inicio de sesión y las rutas de cierre de sesión. Para obtener más información, consulte el Cookieorigen AuthenticationHandler.

Se usa el sistema de protección de datos de ASP.NET Core para el cifrado. En el caso de una aplicación hospedada en varias máquinas, el equilibrio de carga entre aplicaciones o el uso de una granja de servidores web, configure la protección de datos para usar el mismo anillo de claves y el mismo identificador de aplicación.

Cerrar sesión

Para cerrar la sesión del usuario actual y eliminar su cookie, llame a SignOutAsync:

await HttpContext.SignOutAsync(
    CookieAuthenticationDefaults.AuthenticationScheme);

Si CookieAuthenticationDefaults.AuthenticationScheme (o "Cookies") no se usan como esquema (por ejemplo, "ContosoCookie"), proporcione el esquema usado al configurar el proveedor de autenticación. De lo contrario, se usa el esquema predeterminado.

Cuando el explorador se cierra, elimina automáticamente los cookie basados en sesión (cookie no persistentes), pero no se borran cookie cuando se cierra una pestaña individual. El servidor no recibe notificaciones de eventos de cierre de pestaña o explorador.

Reaccionar a los cambios de back-end

Una vez creado cookie, cookie es el único origen de identidad. Si una cuenta de usuario está deshabilitada en sistemas back-end:

  • El sistema de autenticación cookie de la aplicación continúa procesando solicitudes basadas en la autenticación cookie.
  • El usuario permanece conectado a la aplicación siempre que la autenticación cookie sea válida.

El evento ValidatePrincipal se puede usar para interceptar e invalidar la validación de la identidad cookie. Validar cookie en cada solicitud mitiga el riesgo de que los usuarios revocados accedan a la aplicación.

Un enfoque para la validación cookie se basa en realizar un seguimiento de cuándo cambia la base de datos de usuario. Si no se ha cambiado la base de datos desde que se emitió el cookie del usuario, no es necesario volver a autenticar al usuario si su cookie sigue siendo válido. En la aplicación de ejemplo, la base de datos se implementa en IUserRepository y almacena un valor LastChanged. Cuando un usuario se actualiza en la base de datos, el valor LastChanged se establece en la hora actual.

Para invalidar cookie cuando la base de datos cambia en función del valor LastChanged, cree cookie con una notificación LastChanged que contenga el valor actual LastChanged de la base de datos:

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, user.Email),
    new Claim("LastChanged", {Database Value})
};

var claimsIdentity = new ClaimsIdentity(
    claims, 
    CookieAuthenticationDefaults.AuthenticationScheme);

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme, 
    new ClaimsPrincipal(claimsIdentity));

Para implementar una invalidación para el evento ValidatePrincipal, escriba un método con la siguiente firma en una clase que derive de CookieAuthenticationEvents:

ValidatePrincipal(CookieValidatePrincipalContext)

A continuación se muestra una implementación de ejemplo de CookieAuthenticationEvents:

using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;

public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
    private readonly IUserRepository _userRepository;

    public CustomCookieAuthenticationEvents(IUserRepository userRepository)
    {
        // Get the database from registered DI services.
        _userRepository = userRepository;
    }

    public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
    {
        var userPrincipal = context.Principal;

        // Look for the LastChanged claim.
        var lastChanged = (from c in userPrincipal.Claims
                           where c.Type == "LastChanged"
                           select c.Value).FirstOrDefault();

        if (string.IsNullOrEmpty(lastChanged) ||
            !_userRepository.ValidateLastChanged(lastChanged))
        {
            context.RejectPrincipal();

            await context.HttpContext.SignOutAsync(
                CookieAuthenticationDefaults.AuthenticationScheme);
        }
    }
}

Registre la instancia de eventos durante el registro del servicio cookie en el método Startup.ConfigureServices. Proporcione un registro de servicio con ámbito para la clase CustomCookieAuthenticationEvents:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.EventsType = typeof(CustomCookieAuthenticationEvents);
    });

services.AddScoped<CustomCookieAuthenticationEvents>();

Considere una situación en la que se actualiza el nombre del usuario, una decisión que no afecta a la seguridad de ninguna manera. Si desea actualizar de forma no destructiva la entidad de seguridad de usuario, llame a context.ReplacePrincipal y establezca la propiedad context.ShouldRenew en true.

Advertencia

El enfoque descrito aquí se desencadena en cada solicitud. La validación de autenticación cookie para todos los usuarios en cada solicitud puede provocar una gran penalización de rendimiento para la aplicación.

cookie persistente

Es posible que desee que cookie persista en las sesiones del explorador. Esta persistencia solo debe habilitarse con el consentimiento explícito del usuario con una casilla "Recordarme" al iniciar sesión o un mecanismo similar.

El siguiente fragmento de código crea una identidad y el cookie correspondiente que sobrevive a través de cierres del explorador. Se respetan las opciones de expiración deslizante configuradas anteriormente. Si cookie expira mientras se cierra el explorador, el explorador borra cookie una vez reiniciado.

Establezca IsPersistent en true en AuthenticationProperties:

// using Microsoft.AspNetCore.Authentication;

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity),
    new AuthenticationProperties
    {
        IsPersistent = true
    });

Se puede establecer una hora de expiración absoluta con ExpiresUtc. Para crear un objeto persistente cookie, IsPersistent también debe establecerse. De lo contrario, cookie se crea con una duración basada en sesión y podría expirar antes o después del vale de autenticación que contiene. Cuando ExpiresUtc se establece, invalida el valor de la opción ExpireTimeSpan de CookieAuthenticationOptions, si se establece.

El siguiente fragmento de código crea una identidad y el cookie correspondiente que dura 20 minutos. Esto omite cualquier configuración de expiración deslizante configurada anteriormente.

// using Microsoft.AspNetCore.Authentication;

await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity),
    new AuthenticationProperties
    {
        IsPersistent = true,
        ExpiresUtc = DateTime.UtcNow.AddMinutes(20)
    });