.NET  8 - Autenticação e Autorização


  Neste artigo vou apresentar os novos recursos do .NET 8 relacionados ao Identity :  a autenticação e autorização.

Já faz muitos anos que os desenvolvedores ASP.NET Core têm na ASP.NET Core Identity(Identity)  um framweork integrado para adicionar suporte para autenticação e autorização local.

O Identity inclui tudo o que os desenvolvedores normalmente precisam para autenticar e autorizar usuários em um repositório de usuários local, e,  por padrão, um banco de dados SQL Server é criado no Windows e um banco de dados SQLite é criado no macOS, mas você pode alterá-lo para o SGBD de sua preferência.

O Identity foi projetada para aplicativos Web renderizados por servidor, como aplicativos ASP.NET Core MVC ou Razor Pages, e tem desafios com SPAs, onde a autenticação baseada em token parece mais apropriada. Para resolver esse problema, a Microsoft forneceu modelos de projeto integrados para SPAs baseados em Angular e React com suporte ao Identity Server desde o .NET Core 3.1.

No entanto, a comunidade .NET não ficou totalmente satisfeita com esta abordagem. Para atender às demandas da comunidade, a Microsoft removeu o suporte padrão para Identity Server no .NET 8 e redesenhou a arquitetura interna do ASP.NET Core Identity para ser mais adequada para SPAs e aplicativos nativos.

O .NET 8 apresenta um novo conjunto de endpoints de API de identidade e suporte para autenticação baseada em token que irei apresentar a seguir.

Manipulador Bearer Token Authentication

O primeiro alicerce desta nova infraestrutura é o novo manipulador de autenticação de token ao portador. Esse manipulador é semelhante ao manipulador clássico de autenticação de cookie que o ASP.NET Core Identity usa por padrão. O manipulador de autenticação de cookie é responsável por duas coisas:

1- Criar de um novo cookie de sessão após a autenticação do usuário;
2- Construir um objeto de usuário ClaimsPrincipal com base em um cookie de sessão válido recebido na solicitação HTTP recebida;

Da mesma forma, o manipulador de autenticação do token ao portador é responsável por:

Em outras palavras, o manipulador bearer token imita o comportamento do manipulador de cookies para gerenciar sessões autenticadas com base em um token em vez de um cookie.

Cabe destacar que os tokens gerados pelo manipulador bearer token não estão no formato JWT. Além disso, eles não seguem nenhum padrão específico. Embora a documentação mencione tokens de acesso e tokens de atualização, eles não implementam a estrutura de autorização do OAuth 2.0.

Como o bearer token funciona

Vamos criar um novo projeto ASP.NET Core Web API usando o VS 2022 Preview usando o .NET 8. Vamos chamar este projeto Net8Identity onde vamos usar as minimal APIs.

Após criar o projeto vamos incluir o código abaixo na classe Program:

using Microsoft.AspNetCore.Authentication.BearerToken;
using System.Security.Claims;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services
        .AddAuthentication()
        .AddBearerToken();  
builder.Services.AddAuthorization();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapGet("/login", (string username) =>
{
    var claimsPrincipal = new ClaimsPrincipal(
      new ClaimsIdentity(
        new[] { new Claim(ClaimTypes.Name, username) },
            BearerTokenDefaults.AuthenticationScheme  
      )
    );
    return Results.SignIn(claimsPrincipal);
});
app.MapGet("/user", (ClaimsPrincipal user) =>
{
    return Results.Ok($"Bem-Vindo {user.Identity.Name}!");
})
.RequireAuthorization();
app.Run();

Este aplicativo define dois endpoints de API:

1- O endpoint /login que cria um objeto de usuário ClaimsPrincipal com base no nome de usuário enviado na solicitação HTTP e retorna o resultado do login;

2- O endpoint /user que retorna o nome de usuário do usuário autenticado;

Observe as linhas destacadas no código,  note que temos uma referência ao novo namespace Microsoft.AspNetCore.Authentication.BearerToken, que dá acesso ao valor BearerTokenDefaults.AuthenticationScheme

Observe também que configuramos o middleware do token de acesso usando o método de extensão AddBearerToken().

Agora, suponha que você chame o endpoint de login com curl, conforme mostrado abaixo:

curl 'https://localhost:XXXX/login?username=macoratti'

Ou se preferir usar a interface do Swagger:

Você deverá obter o seguinte resultado na interface do Swagger:

A resposta JSON contém :

O token de acesso será usado em cada request para acessar os endoints protegidos e o refresh token poderá ser usado caso o token de acesso expire e assim você conseguirá obter um novo token de acesso.

Por exemplo, agora você pode chamar o endpoint protegido /user da seguinte maneira usando curl:
 

curl -i https://localhost/user -H 'Authorization: Bearer CfDJ8Ha5YkqG......'

Ou se preferir usar o Postam:

Observe que definimos o cabeçalho Authorization onde estamos enviando o token de acesso (não é um token JWT).

Em resumo, o manipulador de autenticação bearer token facilita muito a configuração da autenticação baseada em token. Este é o alicerce de toda a transição da Identity do ASP.NET para a autenticação baseada em token.

Naturalmente podemos implementar um login mais robusto usando um sistema de armazenamento de informações com um banco de dados local.

A seguir temos outra opção para o endpoint /login que verifica a senha do usuário:

app.MapGet("/login", (string username, string password) =>
{
    if (IsValidUser(username, password))
    {
        var claimsPrincipal = new ClaimsPrincipal(
            new ClaimsIdentity(
                new[] { new Claim(ClaimTypes.Name, username) },
                BearerTokenDefaults.AuthenticationScheme
            )
        );
        return Results.SignIn(claimsPrincipal);
    }
    return Results.Unauthorized("Credenciais inválidas");
});
app.Run();
bool IsValidUser(string username, string password)
{
    // Lógica de validação da senha - exemplo simples com senha fixa
    // Em um ambiente de produção, você deve verificar no seu sistema
    // de armazenamento seguro de senhas (por exemplo, um banco de dados)
    return username == "macoratti" && password == "123456";
}

Pegue o projeto aqui:  Net8Identity.zip

"No dia seguinte João viu a Jesus, que vinha para ele, e disse: Eis o Cordeiro de Deus, que tira o pecado do mundo."
João 1:29

Referências:


José Carlos Macoratti