Explorando la Autenticación Bearer en ASP.NET Core 8

isaacojeda

Isaac Ojeda

Posted on October 20, 2023

Explorando la Autenticación Bearer en ASP.NET Core 8

Introducción

La autenticación y autorización son aspectos fundamentales en el desarrollo de aplicaciones web, y en la versión .NET 8, se ha simplificado la implementación de autenticación mediante Bearer Tokens. En este artículo, exploraremos cómo aprovechar Identity Core y esta nueva funcionalidad para configurar la autenticación de manera rápida y sencilla en aplicaciones .NET Core.

Nota :💡 Aquí te dejo el código fuente de este ejemplo: DevToPosts/IdentityApiAuth at main · isaacOjeda/DevToPosts (github.com)

Autenticación por Bearer Tokens en .NET 8

En la versión .NET 8, se ha facilitado la configuración de autenticación mediante Bearer Tokens. Hasta ahora, los desarrolladores a menudo tenían que realizar esta implementación de forma manual, pero con Identity Core y las nuevas características de .NET 8, es más rápido que nunca tener una solución de autenticación lista para usar.

Para comenzar, necesitaremos los siguientes paquetes (ten en cuenta que las versiones pueden haber cambiado desde la redacción de este artículo):

<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0-rc.2.23480.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0-rc.2.23480.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0-rc.2.23480.1">
  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
  <PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
Enter fullscreen mode Exit fullscreen mode

Los paquetes utilizados incluyen:

  • Identity.EntityFrameworkCore: Este paquete permite integrar Identity Core y Entity Framework para gestionar la identidad de los usuarios.
  • EntityFrameworkCore.SqlServer: Utilizaremos SQL Server como sistema de persistencia para almacenar datos de autenticación.
  • EntityFrameworkCore.Tools: Proporciona herramientas para generar migraciones y scripts de base de datos.
  • Swashbuckle.AspNetCore: Este paquete es necesario para implementar Swagger, que facilita la documentación de la API.

Para mantener nuestro ejemplo sencillo, creamos una clase User que hereda de IdentityUser:

using Microsoft.AspNetCore.Identity;

namespace IdentityApiAuth.Models;

public class User : IdentityUser
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public string? Address { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Además, configuramos el contexto de la base de datos:

using IdentityApiAuth.Models;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace IdentityApiAuth.Data;

public class AppDbContext : IdentityDbContext<User>
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }
}
Enter fullscreen mode Exit fullscreen mode

Configuración de Dependencias

La configuración de dependencias es esencial para generar tokens y refresh tokens. En este punto, debemos configurar los servicios y endpoints necesarios. Gracias a Identity Core, gran parte de esta configuración ya se encuentra disponible de manera predeterminada:

using IdentityApiAuth.Data;
using IdentityApiAuth.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Configuración de Entity Framework Core
builder.Services.AddDbContext<AppDbContext>(options => options
    .UseSqlServer(builder.Configuration.GetConnectionString("Default")));

// Configuración de Autenticación y Autorización
builder.Services
    .AddAuthorization()
    .AddAuthentication()
    .AddBearerToken(IdentityConstants.BearerScheme);

// Configuración de Identity Core
builder.Services
    .AddIdentityCore<User>()
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<AppDbContext>()
    .AddApiEndpoints();

// Configuración de Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
Enter fullscreen mode Exit fullscreen mode

Si estamos en un entorno de desarrollo, habilitamos Swagger y su interfaz de usuario para la documentación:

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
Enter fullscreen mode Exit fullscreen mode

Luego, configuramos los middlewares de autenticación y autorización:

app.UseAuthentication();
app.UseAuthorization();
Enter fullscreen mode Exit fullscreen mode

Por último, definimos los endpoints de la API y las reglas de autorización:

app.MapIdentityApi<User>();

app.MapGet("/", () => Results.Redirect("/swagger"));
app.MapGet("/me", (HttpContext httpContext) =>
{
    return new
    {
        httpContext.User.Identity.Name,
        httpContext.User.Identity.AuthenticationType,
        Claims = httpContext.User.Claims.Select(s => new
        {
            s.Type, s.Value
        }).ToList()
    };
})
.RequireAuthorization();
Enter fullscreen mode Exit fullscreen mode

Probando los Endpoints

Para verificar la implementación exitosa de autenticación por Bearer Tokens en nuestra aplicación, utilizaremos el cliente HTTP Client de Visual Studio Code para realizar diversas pruebas en los siguientes endpoints.

Registro de Usuario

Primero, procederemos a registrar un nuevo usuario en la aplicación. Para ello, haremos una solicitud POST al endpoint {{host}}/register con los siguientes datos de usuario:

### New User
POST {{host}}/register
Content-Type: application/json

{
  "username": "isaac",
  "password": "Passw0rd.1",
  "email": "isaac.ojeda@mail.com"
}
Enter fullscreen mode Exit fullscreen mode

La respuesta exitosa será la siguiente:

HTTP/1.1 200 OK 
Content-Length: 0 
Connection: close 
Date: Fri, 20 Oct 2023 23:11:12 GMT 
Server: Kestrel 
Alt-Svc: h3=":5194"; ma=86400
Enter fullscreen mode Exit fullscreen mode

En este punto, todas las validaciones se realizan según la configuración de Identity Core. Si intentamos repetir el registro con el mismo nombre de usuario, recibiremos un mensaje de error:

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "DuplicateUserName": [
      "Username 'isaac' is already taken."
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Inicio de Sesión

Luego, procederemos al inicio de sesión en la aplicación. Haremos una solicitud POST al endpoint {{host}}/login con las credenciales del usuario:

### Login
POST {{host}}/login
Content-Type: application/json

{
    "username": "isaac",
    "password": "Passw0rd.1"
}
Enter fullscreen mode Exit fullscreen mode

La respuesta será un token de acceso (Bearer Token) que se utilizará en llamadas posteriores:

{
  "token_type": "Bearer",
  "access_token": "CfDJ8BO1QsNIvpdOgb3Usybzpi...",
  "expires_in": 3600,
  "refresh_token": "CfDJ8BO1QsNIvpdOgb3Usybzp..."
}
Enter fullscreen mode Exit fullscreen mode

Este token de acceso se debe incluir en el encabezado de autorización (Authorization) en todas las solicitudes que requieran autenticación, como el endpoint /me

Consulta de Datos del Usuario Autenticado

Para obtener información sobre el usuario autenticado, haremos una solicitud GET al endpoint {{host}}/me. Esta solicitud debe incluir el Bearer Token en el encabezado de autorización:

GET {{host}}/me
Content-Type: application/json
Authorization: Bearer {{token}}
Enter fullscreen mode Exit fullscreen mode

La respuesta contendrá detalles del usuario, como su nombre, tipo de autenticación y claims (reclamaciones):

{
  "name": "isaac",
  "authenticationType": "Identity.Application",
  "claims": [
    {
      "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
      "value": "35daf905-8445-40fa-8500-32686311035c"
    },
    {
      "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
      "value": "isaac"
    },
    {
      "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
      "value": "isaac.ojeda@mail.com"
    },
    {
      "type": "AspNet.Identity.SecurityStamp",
      "value": "7RONWQSKG3MRMSLN65345U623KOHH4A3"
    },
    {
      "type": "amr",
      "value": "pwd"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Renovación de Token (Refresh Token)

Si necesitas renovar un token de acceso, puedes hacerlo a través del endpoint /refresh. Realiza una solicitud POST al endpoint con el token de refresco (refresh token):

### Refresh
POST {{host}}/refresh
Content-Type: application/json

{
  "refreshToken": "{{refresh}}"
}
Enter fullscreen mode Exit fullscreen mode

La respuesta contendrá un nuevo token de acceso y su respectivo refresh token:

{
  "token_type": "Bearer",
  "access_token": "CfDJ8BO1QsNIvpdOgb3U...",
  "expires_in": 3600,
  "refresh_token": "CfDJ8BO1QsNIvpdOgb3..."
}
Enter fullscreen mode Exit fullscreen mode

Explora Más Endpoints

Para una experiencia completa, te recomendamos explorar la documentación de Swagger o su definición para descubrir todos los endpoints disponibles en esta implementación. Encontrarás una variedad de endpoints útiles que pueden adaptarse a tus necesidades y mejorar la funcionalidad de tu aplicación.

Conclusión

En este artículo, hemos explorado cómo configurar la autenticación mediante Bearer Tokens en .NET 8 de manera rápida y sencilla. Gracias a Identity Core y las nuevas características de .NET 8, podemos implementar una solución de autenticación eficaz y documentar nuestra API con Swagger. Esta mejora simplifica significativamente el proceso de autenticación y autorización en aplicaciones .NET Core, lo que es beneficioso tanto para desarrolladores como para usuarios.

Referencias

💖 💪 🙅 🚩
isaacojeda
Isaac Ojeda

Posted on October 20, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related