
Neste artigo explorar o conceito de AuthGuard , — uma abordagem personalizada para autenticar rotas — e demonstra como proteger um endpoint de API mínima que busca uma lista de produtos de um banco de dados.
Para mostrar isso vamos abordar a criação de uma minimal API, e fazer a adição de um AuthGuard para proteger a rota e a implementação da lógica do guard com trechos de código abrangentes.
Pré-requisitos :
– SDK do .NET 6.0 ou posterior
– Um entendimento básico de ASP.NET Core
– EF Core
Configurando o Projeto e o Contexto do Banco de Dados
Criando um novo projeto ASP.NET Core Web API:
dotnet new webapi -n ProductApi
cd ProductApi
Vamos incluir no projeto os pacotes:
dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 9.0.6 Microsoft.AspNetCore.Authentication.JwtBearer
Para fins de demonstração, vamos supor que temos um modelo Product e um DbContext correspondente para interagir com o banco de dados. Aqui está um exemplo simplificado:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public class ProductContext : DbContext
{
public ProductContext(DbContextOptions<ProductContext> options)
: base(options) { }
public DbSet<Product> Products { get; set; }
}Criando uma Minimal API para buscar produtos
Agora vamos criar um endpoint na API para buscar produtos incluindo o código abaixo na classe Program:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<ProductContext>(opt =>
// Para simplificar, usando banco de dados em memória
opt.UseInMemoryDatabase("ProductsDb"));
builder.Services.AddAuthorization();
builder.Services.AddAuthentication();
var app = builder.Build();
app.MapGet("/products", async (ProductContext db) =>
await db.Products.ToListAsync())
.RequireAuthorization(); // É aqui que adicionaremos nosso AuthGuard
app.UseAuthentication();
app.UseAuthorization();
app.Run();Estamos usando Entity Framework Core com um banco de dados em memória para demonstração. A parte crucial aqui é o método .RequireAuthorization(), indicando que a rota está protegida e requer autenticação.
Implementando a Lógica do AuthGuard
O recurso AuthGuard no ASP.NET Core essencialmente envolve a configuração de serviços de autenticação e autorização para proteger suas rotas. Precisamos definir esquemas de autenticação e políticas que serão usados por nossa API para autenticar requisições.
Para este exemplo, vamos supor que estamos usando tokens JWT para autenticação. Você normalmente configuraria o serviço de bearer token JWT no Program.cs ou em um método de configuração dedicado:
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.Text;
...
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8
.GetBytes(builder.Configuration["Jwt:Key"]))
};
});Para complementar a implementação do AuthGuard no ASP.NET Core com autenticação JWT, você precisará fornecer configurações que incluem o emissor (issuer), o público (audience) e uma chave secreta usada para assinar os tokens.
Essas configurações são tipicamente armazenadas no arquivo appsettings.json do seu projeto ASP.NET Core.
O emissor (Jwt:Issuer) é uma string que identifica a entidade principal que emitiu o JWT. É uma forma de garantir que o token foi emitido por uma autoridade confiável.
Aqui está um exemplo de conteúdo do arquivo appsettings.json com a seção de configurações JWT:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Jwt": {
"Key": "minhasupersenhasecretaeocultapraxuxu",
"Issuer": "https://macoratti.com.br",
"Audience": "https://macoratti.net"
}
}Nesta configuração de exemplo temos:
Jwt:Key é sua chave secreta usada para assinar os tokens JWT. Esta deve ser uma string longa, aleatória e mantida segura.
Jwt:Issuer é o emissor do token JWT. Isso pode ser o domínio da sua aplicação ou qualquer identificador que faça sentido para sua aplicação. Ele é usado para validar o campo iss do token.
Jwt:Audience é o destinatário pretendido do token JWT, tipicamente o domínio ou identificador da sua API. Ele é usado para validar o campo aud do token.
Ao configurar o serviço de bearer token JWT em Program.cs, você usa essas configurações para configurar o TokenValidationParameters. A estrutura do ASP.NET Core lê essas configurações de appsettings.json e as usa para validar os tokens recebidos (conforme mostrado no trecho de código acima).
Autenticando Requisições
Com o AuthGuard (autenticação JWT) configurado, qualquer requisição para /products deve incluir um token JWT válido no cabeçalho Authorization.
Veja como um cliente pode buscar dados da rota protegida:
GET /products HTTP/1.1
Host: localhost:5000
Authorization: Bearer <seu_token_jwt_aqui>Somente requisições com um token JWT válido poderão acessar os dados. Requisições sem um token ou com um token inválido serão rejeitadas com o código de status 401 Unauthorized.
Ao implementar um AuthGuard usando os mecanismos de autenticação e autorização do ASP.NET Core, você pode proteger seus endpoints de forma eficaz. Este artigo demonstrou uma abordagem prática para adicionar um AuthGuard a uma API mínima para buscar uma lista de produtos de um banco de dados, focando na simplicidade e modularidade dos recursos de segurança do ASP.NET Core.
Observação: a chave para uma segurança eficaz não é apenas adicionar camadas de proteção, mas também entender e configurá-las adequadamente para atender às necessidades da sua aplicação.
Para que um cliente possa acessar nosso endpoint /products protegido, ele primeiro precisa obter um token JWT. Isso é feito geralmente através de um endpoint de login ou autenticação, onde o cliente envia suas credenciais (usuário e senha) e, se válidas, recebe um token de volta.
Acessando a API Protegida (Geração e Uso do Token)
Para que um cliente possa acessar nosso endpoint /products protegido, ele primeiro precisa obter um token JWT. Isso é feito geralmente através de um endpoint de login ou autenticação, onde o cliente envia suas credenciais (usuário e senha) e, se válidas, recebe um token de volta.
1. Criando um Endpoint de Login/Autenticação (para Gerar o Token)
Para fins de demonstração, criaremos um endpoint POST /login muito simples. Em um cenário real, você validaria as credenciais contra um banco de dados de usuários. Aqui, faremos uma validação “mockada”.
Passo 1: Adicionar um Modelo para as Credenciais de Login
Crie uma nova classe LoginRequest.cs em seu projeto:
namespace ProductApi;
public class LoginRequest
{
public string? Username { get; set; }
public string? Password { get; set; }
}Passo 2: Configurar a Geração do Token JWT no Program.cs
Precisamos de uma lógica para criar o token. Isso envolve definir as claims (informações sobre o usuário), o tempo de expiração e a assinatura do token usando a chave secreta configurada.
Adicione o seguinte código ao seu Program.cs, antes de var app = builder.Build();:
app.MapPost("/login", (LoginRequest loginRequest) =>
{
// Em um cenário real, você validaria o username e password
// contra seu banco de dados ou serviço de identidade.
// Para esta demonstração, vamos simular um usuário válido.
if (loginRequest.Username == "macoratti" && loginRequest.Password == "password123")
{
var issuer = builder.Configuration["Jwt:Issuer"];
var audience = builder.Configuration["Jwt:Audience"];
var key = Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]
?? throw new InvalidOperationException("JWT Key not configured."));
var securityKey = new SymmetricSecurityKey(key);
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
// Adicionar claims (informações sobre o usuário)
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, loginRequest.Username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.Role, "Admin") // Exemplo de claim de role
};
var token = new JwtSecurityToken(
issuer: issuer,
audience: audience,
claims: claims,
expires: DateTime.Now.AddMinutes(30), // Token expira em 30 minutos
signingCredentials: credentials);
var jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
return Results.Ok(new { Token = jwtToken });
}
else
{
return Results.Unauthorized(); // 401 Unauthorized
}
});
Explicação do Endpoint /login:
– Ele recebe um LoginRequest (com Username e Password).
– Faz uma validação “mockada” (testuser, password123).
– Se as credenciais forem válidas, ele constrói um JwtSecurityToken usando as configurações do appsettings.json.
– Adiciona claims (assuntos, IDs, roles) ao token.
– Define um tempo de expiração para o token.
– Assina o token com a chave secreta.
– Retorna o token JWT como uma string na resposta.
2. Acessando a API Protegida Usando o Token
Agora que temos um endpoint para gerar o token, podemos mostrar como um cliente (por exemplo, via Postman, cURL ou código C#) faria as requisições.
Exemplo com cURL (para Linha de Comando)
Passo 1: Obter o Token de Acesso
Primeiro, faça uma requisição POST para o endpoint /login para obter o token:
curl -X POST \
http://localhost:7098/login \
-H 'Content-Type: application/json' \
-d '{
"username": "testuser",
"password": "password123"
}'A resposta será algo parecido com:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0dXNlciIsImp0aSI6Ijkw
YjEwZTc3LTc4ZDUtNGJhMC1hYzQ3LTczZWEwYTdkM2Y5NyIsImh0dHA6Ly9zY2hlbWFzLm
1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluIi
wiZXhwIjoxNzA3MjYzNDkwLCJpc3MiOiJodHRwczovL3lvdXJkb21haW4uY29tIiwiYXVkIjoiaHR
0cHM6Ly95b3VyYXBpLnlvdXJkb21haW4uY29tIn"
}Copie o valor da propriedade “token”.
Passo 2: Usar o Token para Acessar o Endpoint Protegido (/products)
Agora, use o token obtido no cabeçalho Authorization com o prefixo Bearer:
| curl -X GET \ http://localhost:7098/products \ -H ‘Authorization: Bearer <seu_token_jwt_copiado_aqui>’ |







