Usar autenticação cookie sem ASP.NET Core Identity

De Rick Anderson

O ASP.NET Core Identity é um provedor de autenticação completo para criar e manter logins. No entanto, um provedor de autenticação baseado em cookie sem ASP.NET Core Identity pode ser usado. Para obter mais informações, confira Introdução a Identity no ASP.NET Core.

Exibir ou baixar código de exemplo (como baixar)

Para fins de demonstração no aplicativo de exemplo, a conta de usuário do usuário hipotético, Maria Rodriguez, é codificada no aplicativo. Use o endereço de emailmaria.rodriguez@contoso.com e qualquer senha para entrar no usuário. O usuário é autenticado no método AuthenticateUser do arquivo Pages/Account/Login.cshtml.cs. Em um exemplo real, o usuário seria autenticado em um armazenamento de dados.

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 passado para AddAuthentication define o esquema de autenticação padrão do aplicativo. AuthenticationScheme é útil quando há várias instâncias de autenticação cookie e o aplicativo precisa autorizar com um esquema específico. Configurar AuthenticationScheme como CookieAuthenticationDefaults.AuthenticationScheme fornece um valor igual a "Cookies" para o esquema. Qualquer valor de cadeia de caracteres que distingue o esquema pode ser usado.

O esquema de autenticação do aplicativo é diferente do esquema de autenticação cookie do aplicativo. Quando um esquema de autenticação cookie não é fornecido para AddCookie, ele usa CookieAuthenticationDefaults.AuthenticationScheme. A CookieAuthenticationDefaults.AuthenticationScheme Fonte do GitHub mostra que está definido como "Cookies".

A propriedade cookie de autenticação IsEssential é definida como true por padrão. Os cookies de autenticação são permitidos quando um visitante do site não consente a coleta de dados. Para obter mais informações, veja Suporte ao RGPD (Regulamento Geral sobre a Proteção de Dados) no ASP.NET Core.

A classe CookieAuthenticationOptions é usada para configurar as opções do provedor de autenticação.

Configure CookieAuthenticationOptions no 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();

O Cookie Middleware de política (fonte do GitHub) UseCookiePolicy habilita cookie recursos de política. O middleware é processado na ordem em que é adicionado:

app.UseCookiePolicy(cookiePolicyOptions);

Use CookiePolicyOptions fornecido ao CookieMiddleware de política para controlar as características globais do processamento de cookie e conecte-se aos manipuladores de processamento de cookie quando os cookies forem acrescentados ou excluídos.

O valor padrão MinimumSameSitePolicy é SameSiteMode.Lax para permitir a autenticação OAuth2. Para impor estritamente uma política do mesmo site de SameSiteMode.Strict, defina o MinimumSameSitePolicy. Embora essa configuração interrompa o OAuth2 e outros esquemas de autenticação entre origens, ela eleva o nível de segurança do cookie para outros tipos de aplicativos que não dependem do processamento de solicitações entre origens.

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

A configuração do Middleware de política de Cookie para MinimumSameSitePolicy pode afetar a configuração de Cookie.SameSite em configurações CookieAuthenticationOptions de acordo com a matriz abaixo.

MinimumSameSitePolicy Cookie.SameSite Cookie resultante. Configuração 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 criar um cookie que contenha as informações do usuário, construa um ClaimsPrincipal. As informações do usuário são serializadas e armazenadas no cookie.

Crie um ClaimsIdentity com quaisquer Claims necessários e chame SignInAsync para conectar o usuário. O Login.cshtml.cs no aplicativo de amostra contém o seguinte 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();
}

Se você quiser ver os comentários de código traduzidos para idiomas diferentes do inglês, informe-nos neste problema de discussão do GitHub.

SignInAsync cria um cookie criptografado e adiciona-o à resposta atual. Se AuthenticationScheme não for especificado, o esquema padrão será usado.

RedirectUri é usado apenas em alguns caminhos específicos por padrão, por exemplo, o caminho de logon e os caminhos de logoff. Para mais informações, consulte a origem CookieAuthenticationHandler .

O sistema de Proteção de Dados do ASP.NET Core é usado para criptografia. Para um aplicativo hospedado em vários computadores, balanceamento de carga entre aplicativos ou usando um web farm, configure a proteção de dados para usar o mesmo anel de chave e identificador de aplicativo.

Sair

Para fazer logoff do usuário atual e excluir o cookie dele, chame 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;
}

Se CookieAuthenticationDefaults.AuthenticationScheme ou "Cookies" não for usado como o esquema, forneça o esquema usado ao configurar o provedor de autenticação. Caso contrário, o esquema padrão será usado. Por exemplo, se "ContosoCookies" for usado como esquema, forneça o esquema usado ao configurar o provedor de autenticação.

Quando o navegador fecha, ele exclui automaticamente cookies baseados em sessão (cookies não persistentes), mas nenhum cookie é apagado quando uma guia individual é fechada. O servidor não é notificado sobre eventos de fechamento de guia ou de navegador.

Reagir a alterações de back-end

Depois que um cookie for criado, o cookie será a única fonte de identity. Se uma conta de usuário estiver desabilitada em sistemas de back-end:

  • O sistema de autenticação de cookie do aplicativo continua a processar solicitações com base na autenticação cookie.
  • O usuário permanece conectado ao aplicativo, desde que a autenticação cookie seja válida.

O evento ValidatePrincipal pode ser usado para interceptar e substituir a validação da identidade cookieidentity. Validar o cookie em cada solicitação reduz o risco de usuários revogados acessarem o aplicativo.

Uma abordagem para validação cookie baseia-se em manter o controle de quando o banco de dados do usuário é alterado. Se o banco de dados não tiver sido alterado desde que o cookie do usuário foi emitido, não será necessário autenticar novamente o usuário se cookie dele ainda for válido. No aplicativo de exemplo, o banco de dados é implementado em IUserRepository e armazena um valor LastChanged. Quando um usuário é atualizado no banco de dados, o valor LastChanged é definido como a hora atual.

Para invalidar um cookie quando o banco de dados for alterado com base no valor LastChanged, crie o cookie com uma declaração LastChanged que contenha o valor LastChanged atual do banco de dados:

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 uma substituição para o evento ValidatePrincipal, escreva um método com a seguinte assinatura em uma classe derivada de CookieAuthenticationEvents:

ValidatePrincipal(CookieValidatePrincipalContext)

A seguir é um exemplo de implementação 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 a instância de eventos durante o registro do serviço cookie. Forneça um registro de serviço com escopo para sua classe 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 uma situação em que o nome do usuário é atualizado — uma decisão que não afeta a segurança de forma alguma. Se você quiser atualizar de forma não destrutiva a entidade de segurança do usuário, chame context.ReplacePrincipal e defina a propriedade context.ShouldRenew como true.

Aviso

A abordagem descrita aqui é disparada em cada solicitação. Validar cookies de autenticação para todos os usuários em cada solicitação pode resultar em um grande comprometimento de desempenho para o aplicativo.

Cookies persistentes

Talvez você queira que o cookie persista entre as sessões do navegador. Essa persistência só deve ser habilitada com o consentimento explícito do usuário com uma caixa de seleção "Lembrar-me" na entrada ou em um mecanismo semelhante.

O snippet de código a seguir cria uma identity e o cookie correspondente que sobrevive por meio de fechamentos do navegador. Todas as configurações de expiração deslizantes configuradas anteriormente são respeitadas. Se o cookie expirar enquanto o navegador estiver fechado, o navegador limpará o cookie depois de reiniciado.

Defina IsPersistent como true em AuthenticationProperties:

// using Microsoft.AspNetCore.Authentication;

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

Um tempo de expiração absoluto pode ser definido com ExpiresUtc. Para criar um cookie persistente, IsPersistent também deve ser definido. Caso contrário, o cookie será criado com um tempo de vida baseado em sessão e poderá expirar antes ou depois do tíquete de autenticação que ele contém. Quando ExpiresUtc é definido, ele substitui o valor da opção ExpireTimeSpan de CookieAuthenticationOptions, se definido.

O snippet de código a seguir cria uma identity e o cookie correspondente que dura 20 minutos. Isso ignora as configurações de expiração deslizantes configuradas anteriormente.

// using Microsoft.AspNetCore.Authentication;

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

O ASP.NET Core Identity é um provedor de autenticação completo para criar e manter logins. No entanto, um provedor de autenticação baseado em cookie sem ASP.NET Core Identity pode ser usado. Para obter mais informações, confira Introdução a Identity no ASP.NET Core.

Exibir ou baixar código de exemplo (como baixar)

Para fins de demonstração no aplicativo de exemplo, a conta de usuário do usuário hipotético, Maria Rodriguez, é codificada no aplicativo. Use o endereço de emailmaria.rodriguez@contoso.com e qualquer senha para entrar no usuário. O usuário é autenticado no método AuthenticateUser do arquivo Pages/Account/Login.cshtml.cs. Em um exemplo real, o usuário seria autenticado em um banco de dados.

Configuração

No método Startup.ConfigureServices, crie os serviços do Middleware de autenticação com os métodos AddAuthentication e AddCookie:

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

AuthenticationScheme passado para AddAuthentication define o esquema de autenticação padrão do aplicativo. AuthenticationScheme é útil quando há várias instâncias de autenticação cookie e deseja autorizar com um esquema específico. Configurar AuthenticationScheme como CookieAuthenticationDefaults.AuthenticationScheme fornece um valor de "Cookies" para o esquema. Você pode fornecer qualquer valor de cadeia de caracteres que distingue o esquema.

O esquema de autenticação do aplicativo é diferente do esquema de autenticação cookie do aplicativo. Quando um esquema de autenticação cookie não é fornecido para AddCookie, ele usa CookieAuthenticationDefaults.AuthenticationScheme ("Cookies").

A propriedade cookie de autenticação IsEssential é definida como true por padrão. Os cookies de autenticação são permitidos quando um visitante do site não consente a coleta de dados. Para obter mais informações, veja Suporte ao RGPD (Regulamento Geral sobre a Proteção de Dados) no ASP.NET Core.

Em Startup.Configure, chame UseAuthentication e UseAuthorization para definir a propriedade HttpContext.User e execute o Middleware de autorização para solicitações. Chame os métodos UseAuthentication e UseAuthorization antes de chamar UseEndpoints:

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

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

A classe CookieAuthenticationOptions é usada para configurar as opções do provedor de autenticação.

Defina na configuração do serviço CookieAuthenticationOptions para autenticação no método Startup.ConfigureServices:

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

O Middleware de política Cookie habilita os recursos de política cookie. A adição do middleware ao pipeline de processamento de aplicativos diferencia a ordem, afetando apenas os componentes downstream registrados no pipeline.

app.UseCookiePolicy(cookiePolicyOptions);

Use CookiePolicyOptions fornecido ao CookieMiddleware de política para controlar as características globais do processamento de cookie e conecte-se aos manipuladores de processamento de cookie quando os cookies forem acrescentados ou excluídos.

O valor padrão MinimumSameSitePolicy é SameSiteMode.Lax para permitir a autenticação OAuth2. Para impor estritamente uma política do mesmo site de SameSiteMode.Strict, defina o MinimumSameSitePolicy. Embora essa configuração interrompa o OAuth2 e outros esquemas de autenticação entre origens, ela eleva o nível de segurança do cookie para outros tipos de aplicativos que não dependem do processamento de solicitações entre origens.

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

A configuração do Middleware de política de Cookie para MinimumSameSitePolicy pode afetar a configuração de Cookie.SameSite em configurações CookieAuthenticationOptions de acordo com a matriz abaixo.

MinimumSameSitePolicy Cookie.SameSite Cookie resultante. Configuração 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 criar um cookie que contenha as informações do usuário, construa um ClaimsPrincipal. As informações do usuário são serializadas e armazenadas no cookie.

Crie um ClaimsIdentity com qualquer Claims necessário e chame SignInAsync para conectar o usuário:

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);

Se você quiser ver os comentários de código traduzidos para idiomas diferentes do inglês, informe-nos neste problema de discussão do GitHub.

SignInAsync cria um cookie criptografado e adiciona-o à resposta atual. Se AuthenticationScheme não for especificado, o esquema padrão será usado.

RedirectUri é usado apenas em alguns caminhos específicos por padrão, por exemplo, o caminho de logon e os caminhos de logoff. Para mais informações, consulte a origem CookieAuthenticationHandler .

O sistema de Proteção de Dados do ASP.NET Core é usado para criptografia. Para um aplicativo hospedado em vários computadores, balanceamento de carga entre aplicativos ou usando um web farm, configure a proteção de dados para usar o mesmo anel de chave e identificador de aplicativo.

Sair

Para fazer logoff do usuário atual e excluir o cookie dele, chame SignOutAsync:

await HttpContext.SignOutAsync(
    CookieAuthenticationDefaults.AuthenticationScheme);

Se CookieAuthenticationDefaults.AuthenticationScheme (ou "Cookies") não for usado como esquema (por exemplo, "ContosoCookie"), forneça o esquema usado ao configurar o provedor de autenticação. Caso contrário, o esquema padrão será usado.

Quando o navegador fecha, ele exclui automaticamente cookies baseados em sessão (cookies não persistentes), mas nenhum cookie é apagado quando uma guia individual é fechada. O servidor não é notificado sobre eventos de fechamento de guia ou de navegador.

Reagir a alterações de back-end

Depois que um cookie for criado, o cookie será a única fonte de identity. Se uma conta de usuário estiver desabilitada em sistemas de back-end:

  • O sistema de autenticação de cookie do aplicativo continua a processar solicitações com base na autenticação cookie.
  • O usuário permanece conectado ao aplicativo, desde que a autenticação cookie seja válida.

O evento ValidatePrincipal pode ser usado para interceptar e substituir a validação da identidade cookieidentity. Validar o cookie em cada solicitação reduz o risco de usuários revogados acessarem o aplicativo.

Uma abordagem para validação cookie baseia-se em manter o controle de quando o banco de dados do usuário é alterado. Se o banco de dados não tiver sido alterado desde que o cookie do usuário foi emitido, não será necessário autenticar novamente o usuário se cookie dele ainda for válido. No aplicativo de exemplo, o banco de dados é implementado em IUserRepository e armazena um valor LastChanged. Quando um usuário é atualizado no banco de dados, o valor LastChanged é definido como a hora atual.

Para invalidar um cookie quando o banco de dados for alterado com base no valor LastChanged, crie o cookie com uma declaração LastChanged que contenha o valor LastChanged atual do banco de dados:

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 uma substituição para o evento ValidatePrincipal, escreva um método com a seguinte assinatura em uma classe derivada de CookieAuthenticationEvents:

ValidatePrincipal(CookieValidatePrincipalContext)

A seguir é um exemplo de implementação 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 a instância de eventos durante o registro do serviço cookie no método Startup.ConfigureServices. Forneça um registro de serviço com escopo para sua classe CustomCookieAuthenticationEvents:

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

services.AddScoped<CustomCookieAuthenticationEvents>();

Considere uma situação em que o nome do usuário é atualizado — uma decisão que não afeta a segurança de forma alguma. Se você quiser atualizar de forma não destrutiva a entidade de segurança do usuário, chame context.ReplacePrincipal e defina a propriedade context.ShouldRenew como true.

Aviso

A abordagem descrita aqui é disparada em cada solicitação. Validar cookies de autenticação para todos os usuários em cada solicitação pode resultar em um grande comprometimento de desempenho para o aplicativo.

Cookies persistentes

Talvez você queira que o cookie persista entre as sessões do navegador. Essa persistência só deve ser habilitada com o consentimento explícito do usuário com uma caixa de seleção "Lembrar-me" na entrada ou em um mecanismo semelhante.

O snippet de código a seguir cria uma identity e o cookie correspondente que sobrevive por meio de fechamentos do navegador. Todas as configurações de expiração deslizantes configuradas anteriormente são respeitadas. Se o cookie expirar enquanto o navegador estiver fechado, o navegador limpará o cookie depois de reiniciado.

Defina IsPersistent como true em AuthenticationProperties:

// using Microsoft.AspNetCore.Authentication;

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

Um tempo de expiração absoluto pode ser definido com ExpiresUtc. Para criar um cookie persistente, IsPersistent também deve ser definido. Caso contrário, o cookie será criado com um tempo de vida baseado em sessão e poderá expirar antes ou depois do tíquete de autenticação que ele contém. Quando ExpiresUtc é definido, ele substitui o valor da opção ExpireTimeSpan de CookieAuthenticationOptions, se definido.

O snippet de código a seguir cria uma identity e o cookie correspondente que dura 20 minutos. Isso ignora as configurações de expiração deslizantes configuradas anteriormente.

// using Microsoft.AspNetCore.Authentication;

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