La autorización es el proceso de decidir si una identidad puede realizar una acción a partir de claims, roles o políticas.
En el artículo anterior logramos que el usuario iniciara sesión y obtuviera su JWT. Ese token es como su pasaporte: contiene datos sobre su identidad.
Tener pasaporte no significa que puedas entrar a la cabina del piloto.
En este punto aparece la Autorización Granular. No nos basta con saber que el usuario está logueado ([Authorize]); necesitamos saber si tiene permiso para borrar ese producto o ver esa factura.
Para ello, ASP.NET Core utiliza tres conceptos que a menudo se confunden: Claims (Afirmaciones), Roles y Policies (Políticas). Hoy vamos a dominarlos.
Qué es un claim
Un Claim es simplemente un dato: un par clave-valor que describe algo sobre el usuario. Piensa en tu DNI o Licencia de Conducir. Tiene varios “Claims”:
- Nombre: Luis
- Fecha de Nacimiento: 01/01/1985
- Puede Conducir Motos: Sí
En el mundo JWT, estos datos viajan dentro del Payload del token.
{
"sub": "123",
"email": "[email protected]",
"role": "Admin",
"vip": "true"
}Cuando ASP.NET valida el token, extrae estos datos y construye un objeto User (de tipo ClaimsPrincipal) que tienes disponible en todos tus controladores.
Leer claims en el controlador
¿Necesitas saber el ID del usuario actual para filtrar sus pedidos? Ese dato suele venir en el token y puedes leerlo desde User.
[Authorize]
[HttpGet("mis-datos")]
public IActionResult GetMisDatos()
{
// User es una propiedad disponible en ControllerBase
// Forma 1: Buscar por tipo estándar
var id = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var email = User.FindFirst(ClaimTypes.Email)?.Value;
// Forma 2: Buscar un claim personalizado
var esVip = User.FindFirst("vip")?.Value;
return Ok($"Hola usuario {id}, tu email es {email}");
}Usar claims evita viajes innecesarios a la base de datos, pero solo para datos estables y no sensibles. Si el dato cambia a menudo o afecta a una decisión crítica, valida contra tu sistema de permisos.
Autorización basada en roles
El enfoque más tradicional es asignar a cada usuario una etiqueta: “Admin”, “User”, “Manager”. En ASP.NET Core, esto es extremadamente fácil de implementar.
Solo tienes que asegurarte de que, al generar el token (en el artículo anterior), añadiste el claim de tipo Rol:
new Claim(ClaimTypes.Role, "Admin")Ahora, puedes proteger tus rutas así:
// Solo usuarios con el Claim Role = "Admin"
[Authorize(Roles = "Admin")]
[HttpDelete("{id}")]
public IActionResult BorrarProducto(int id)
{
return Ok("Producto borrado");
}
// Usuarios que sean Admin O Manager
[Authorize(Roles = "Admin,Manager")]
[HttpPut("{id}")]
public IActionResult EditarProducto(int id) { ... }Si un usuario con rol “User” intenta llamar a BorrarProducto, recibirá automáticamente un 403 Forbidden.
Autorización basada en políticas
Los Roles están bien para empezar, pero se quedan cortos rápido. ¿Qué pasa si quieres que un usuario pueda borrar productos solo si es mayor de edad? ¿O si tiene una suscripción “Pro”? ¿Vas a crear un rol “AdminMayorDeEdadPro”? Eso no escala.
Para eso existen las Políticas (Policies).
Una política es una regla lógica que definimos en el Program.cs y luego aplicamos en los controladores. Desacopla la regla (“PuedeBorrar”) de la implementación (“Es Admin”).
En Program.cs, al configurar los servicios:
builder.Services.AddAuthorization(options =>
{
// Política 1: Solo admins (igual que Roles, pero encapsulado)
options.AddPolicy("EsAdmin", policy => policy.RequireRole("Admin"));
// Política 2: Usuarios VIP (Claim personalizado 'vip' == 'true')
options.AddPolicy("EsVip", policy => policy.RequireClaim("vip", "true"));
// Política 3: Lógica más compleja (ej: Antigüedad > 2 años)
// Esto requiere 'Requirements' personalizados que veremos en cursos avanzados
});En el controlador, en lugar de Roles, usamos Policy.
[Authorize(Policy = "EsAdmin")]
[HttpDelete]
public IActionResult Borrar() { ... }
[Authorize(Policy = "EsVip")]
[HttpGet("ofertas-especiales")]
public IActionResult GetOfertas() { ... }La ventaja es que si mañana decides que para “Borrar” no hace falta ser Admin, sino que basta con ser “Supervisor”, solo cambias la definición de la política en Program.cs. No tienes que tocar los 50 controladores donde usaste el atributo.
Cuándo usar cada opción
| Herramienta | Uso | Ejemplo |
|---|---|---|
| Claims | Para leer datos del usuario | User.FindFirst("email") |
| Roles | Para permisos simples y jerárquicos | [Authorize(Roles="Admin")] |
| Policies | Para reglas de negocio o lógica compleja | [Authorize(Policy="PuedeExportarExcel")] |
Para APIs pequeñas, los roles directos son suficientes. Cuando la autorización empieza a tener reglas de negocio, las políticas suelen escalar mejor porque concentran la decisión en un solo sitio.