ASP.NET
- Manipulador de autenticação Bearer Token
![]() |
Neste artigo vou apresentar o novo manipulador de autenticação Bearer Token. |
O Identity foi projetado para aplicações Web renderizadas por servidor, e possui desafios com aplicações Single Page Applications, onde a autenticação baseada em token parece ser mais pertinente
Para resolver esse problema, a Microsoft forneceu modelos de projeto integrados para aplicações SPAs baseadas em Angular e React com suporte ao Identity Server desde o .NET Core 3.1. No entanto, parece que a comunidade .NET não ficou totalmente satisfeita com esta abordagem.
Assim, no Net 8.0, a Microsoft removeu o suporte padrão para Identity Server e redesenhou a arquitetura interna da ASP.NET Core Identity para ser mais adequada para aplicações nativas e aplicações SPAs .
Novo manipulador bearer token
No .NET 8 a
ASP.NET Core 8 apresenta o novo manipulador de autenticação bearer token.
Esse manipulador é semelhante ao manipulador clássico de autenticação de cookie
que a ASP.NET Core Identity usa por padrão
Ele é Responsável por:
1 - Criar de um
novo token após a autenticação do usuário;
2 - Construir um objeto de usuário ClaimsPrincipal com base em um token válido
recebido no request HTTP;
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.
Obs: Cabe destacar que os tokens gerados
pelo manipulador bearer token não estão no formato JWT.
Como funciona a autenticação via cookies ?
Vamos recordar como é feita a autenticação via cookies.
- Após de realizar a autenticação do usuário a aplicação emite um cookie de
sessão
- Este cookie contém sua identidade de usuário na forma de ClaimsPrincipal.
- O conteúdo do cookie é protegido e criptografado usando a API integrada de
proteção de dados.
- O emissor deste cookie é o manipulador de autenticação de cookies.
- Este manipulador tem dois propósitos principais:
- Quando um usuário é autenticado, o manipulador emite um novo cookie de sessão
com base nos detalhes do usuário fornecidos
Assim a autentição
dos requests recebidos é feita procurando por um cookie de sessão.
Se um cookie válido for encontrado, ele criará um objeto de usuário
ClaimsPrincipal com base nas informações contidas
no cookie. Esse objeto de usuário é então passado pelo pipeline de request da
ASP.NET Core
e o request é validado.
Desta forma,
atualmente, os sistemas dependem do cookie de sessão para autenticar as
requisições dos usuários. Isso significa que você é forçado a usar a interface
do usuário fornecida pelo servidor backend, com poucas opções de personalização.
Isso geralmente resulta em uma experiência inconsistente para os usuários quando
eles fazem a transição de uma experiência de aplicativo baseada em navegador
para uma experiência renderizada em servidor.
Assim os objetivos do manipulador bearer Token são :
1- Melhorar a autenticação baseada em cookies:
Introduzindo mais personalização e experiência de usuário consistente
entre aplicativos de página única e renderizados no servidor.
2- Introduzir a autenticação baseada em token:
Alterar a autenticação baseada em cookies para um sistema de autenticação
baseado em token mais flexível e amplamente usado
Com isso, o novo manipulador Bearer Token pode ser visto como uma alternativa ao manipulador de cookies, mas com uma diferença. Em vez de emitir cookies, ele emite um token de acesso e atualização. que devem ser usados entre o cliente e as aplicações.
O manipulador
Bearer Token não pretende ser um componente
independente. Em vez disso, ele deve ser usado com o Identity integrando outros
recursos.
Na ASP.NET Core, agora temos três manipuladores que fazem quase a mesma coisa.
1- O manipulador de cookies
2- O manipulador de token JWT Bearer
3- O manipulador Bearer Token
Todos os três visam autenticar requisições de usuários e podem ser usados em aplicações ASP.NET Core.
Criando o projeto no Visual Studio
Agora eu vou
mostrar um exemplo prático e básico de utilização do manipulador bearer token.
Vamos criar um projeto ASP.NET Core Web API no VS 2022
preview chamado Net8BearerToken usando o
.NET 8.0.
Na classe Program vamos usar o método de extensão
AddBearerToken para configurar o middleware de
autenticação com o manipulador do token de acesso :
builder.Services.AddAuthentication().AddBearerToken();
A seguir vamos adicionar os serviços de autorização :
builder.Services.AddAuthorization();
E, para permitir que a interface do swagger recebe a informação do token
vamos alterar a a configuração do addSwaggerGen()
conforme abaixo:
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "apinet8", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Name = "Authorization",
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "Token",
In = ParameterLocation.Header,
Description = "Token Access",
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] {}
}
});
});
|
Eu não vou usar um banco de dados para armazenar as informações do usuário, nem vou gerar os endpoints para o refresh token e para o registro do usuário.
Na pasta Controllers vamos criar o controlador AuthController com o seguinte código:
using Microsoft.AspNetCore.Authentication.BearerToken;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace Net8BearerToken.Controllers;
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
[HttpGet("/login")]
public IActionResult Login(string username, string password)
{
if (IsValidUser(username, password))
{
var claimsPrincipal = new ClaimsPrincipal(
new ClaimsIdentity(
new[] { new Claim(ClaimTypes.Name, username) },
BearerTokenDefaults.AuthenticationScheme
)
);
return SignIn(claimsPrincipal);
}
return Unauthorized("Credenciais inválidas");
}
private bool IsValidUser(string username, string password)
{
return username == "macoratti" && password == "123456";
}
[HttpGet("/user")]
[Authorize]
public IActionResult GetUser()
{
var user = User;
if (user?.Identity?.IsAuthenticated ?? false)
{
return Ok($"Bem-Vindo {user.Identity.Name}!");
}
return Unauthorized();
}
}
|
Neste código criamos o endpoint para 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;
- var claimsPrincipal = new ClaimsPrincipal(...);
Se as credenciais são válidas, um objeto ClaimsPrincipal
é criado. Este é um objeto que representa a identidade do usuário e é comumente
usado para autenticação e autorização.
- new ClaimsIdentity(...);
Um objeto ClaimsIdentity é criado, que representa
as reivindicações (claims) associadas ao usuário. No caso, apenas uma
reivindicação é adicionada, indicando o nome do usuário.
Estamos definindo o esquema de autenticação usado para criar o ClaimsIdentity.
Neste caso, está sendo utilizado o esquema Bearer Token.
- return SignIn(claimsPrincipal);
A função SignIn é chamada para efetuar a
autenticação do usuário. O objeto ClaimsPrincipal é
passado como parâmetro para indicar a identidade do usuário autenticado.
O segundo endpoint
permite obter informações do usuário autenticado. A ação é protegida pelo
atributo [Authorize], garantindo que apenas
usuários autenticados possam acessar essa funcionalidade
var user = User;
Aqui, obtemos o objeto ClaimsPrincipal associado ao
usuário atual. User é uma propriedade que retorna a
ClaimsPrincipal associado ao request atual.
if (user?.Identity?.IsAuthenticated ?? false) { ... }
Verificamos se o usuário está autenticado, e se estiver, ele continua a executar o código dentro desse bloco
return Unauthorized();
Se o usuário não estiver autenticado, a ação retorna um resultado
HTTP 401 (Unauthorized).
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.
Na classe Program vamos definir o código para configurar o middleware do token:
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
...
builder.Services.AddAuthentication().AddBearerToken();
builder.Services.AddAuthorization();
var app = builder.Build(); ... app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
|
A configuração é feita usando o método de extensão
AddBearerToken().
Executando o projeto teremos o seguinte resultado:
Acionando o endpoint GET /login e informando as credenciais:
Ao clicar em execute temos as seguintes informações geradas:
O token de acesso do tipo Bearer a data de expiração e o refresh token.
Vamos usar o token para acessar o endpoint /user que esta protegido.
Acessando o endpoint GET /user
Pegue o projeto
aqui:
https://github.com/macoratti/Net8-BearerToken
"Jesus disse-lhes: A minha comida é fazer a vontade daquele que me enviou, e
realizar a sua obra."
João 4:34
Referências:
C# - Tasks x Threads. Qual a diferença
DateTime - Macoratti.net
Null o que é isso ? - Macoratti.net
Formatação de data e hora para uma cultura ...
C# - Calculando a diferença entre duas datas
NET - Padrão de Projeto - Null Object Pattern
C# - Fundamentos : Definindo DateTime como Null ...
C# - Os tipos Nullable (Tipos Anuláveis)