1. Autenticação vs. autorização
| Autenticação | Autorização | |
|---|---|---|
| Pergunta que responde | Quem é você? | O que você pode fazer? |
| Quando acontece | Uma vez, no login | A cada requisição, para cada recurso |
| Falha típica | 401 Unauthorized | 403 Forbidden |
2. JWT — carregando identidade sem guardar sessão no servidor
Lembrando o capítulo 1 (APIs são stateless): o servidor não guarda "quem está logado" em memória entre requisições. Um JWT (JSON Web Token) resolve isso — é um token assinado digitalmente que carrega a identidade do usuário dentro dele mesmo, verificável sem consultar um banco a cada requisição.
Fig. 1 — Um JWT é as três partes separadas por ponto: header.payload.signature — só o servidor consegue gerar uma assinatura válida.
O payload de um JWT é legível por qualquer um (é só Base64, não criptografia) — a assinatura garante apenas que ele não foi alterado depois de emitido. Nunca coloque dados sensíveis (senha, número de cartão) dentro do payload.
3. Gerando um token no login
public string GerarToken(Cliente cliente)
{
var claims = new List<Claim>
{
new(ClaimTypes.NameIdentifier, cliente.Id.ToString()),
new(ClaimTypes.Name, cliente.Nome),
new(ClaimTypes.Role, "Cliente"),
};
var chave = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_chaveSecreta));
var credenciais = new SigningCredentials(chave, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "MinhaApi",
audience: "MeusClientes",
claims: claims,
expires: DateTime.UtcNow.AddHours(2),
signingCredentials: credenciais);
return new JwtSecurityTokenHandler().WriteToken(token);
}
4. Configurando o ASP.NET Core para validar o token
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opcoes =>
{
opcoes.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "MinhaApi",
ValidAudience = "MeusClientes",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(chaveSecreta)),
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication(); // quem é você
app.UseAuthorization(); // o que você pode fazer
Assim como no Módulo 3 (capítulo 7), UseAuthentication() precisa vir
antes de UseAuthorization() no pipeline. Autorização
depende de já saber quem é o usuário.
5. Protegendo endpoints com [Authorize]
[ApiController]
[Route("api/clientes")]
[Authorize] // exige token válido para qualquer endpoint deste controller
public class ClienteController : ControllerBase
{
[HttpGet]
public async Task<ActionResult> Listar() { ... } // qualquer usuário autenticado
[HttpDelete("{id:int}")]
[Authorize(Roles = "Admin")] // só usuários com a role "Admin"
public async Task<IActionResult> Excluir(int id) { ... }
[HttpGet("publico")]
[AllowAnonymous] // exceção — libera mesmo dentro de um controller [Authorize]
public IActionResult InfoPublica() => Ok("Sem necessidade de login");
}
6. Enviando o token do lado do cliente
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", tokenRecebidoNoLogin);
var resposta = await httpClient.GetAsync("api/clientes");
O cabeçalho Authorization: Bearer <token> é o padrão universal
— o mesmo formato que você usaria em qualquer chamada fetch do
JavaScript com um header customizado.
7. Onde isso te leva
Com segurança coberta, o próximo capítulo trata de algo que toda API precisa: documentação viva, que se mantém sincronizada com o código automaticamente através do OpenAPI/Swagger.