Integración de JWT en Blazor WebAssembly

Aquí tienes un artículo redactado sobre la integración de JWT en Blazor WebAssembly, con ejemplos de código comentados y referencias a la documentación pertinente.


La autenticación y autorización son aspectos críticos en el desarrollo de aplicaciones web. JSON Web Tokens (JWT) es un estándar abierto que permite la transmisión de información de forma segura entre dos partes. En este artículo, aprenderemos cómo integrar JWT en una aplicación Blazor WebAssembly, desde la autenticación del usuario hasta la gestión de la sesión.

¿Qué es JWT?

JSON Web Token (JWT) es un formato de token que permite la transmisión de información de forma segura. Consiste en tres partes:

  1. Header (Encabezado): Especifica el tipo de token y el algoritmo de firma.
  2. Payload (Carga útil): Contiene los datos (claims) que queremos transmitir.
  3. Signature (Firma): Se utiliza para verificar que el emisor del token es quien dice ser y para asegurarse de que el mensaje no haya sido alterado.

Para más detalles, puedes consultar la documentación oficial de JWT.

Configuración del Proyecto

Primero, asegúrate de tener un proyecto Blazor WebAssembly. Puedes crear uno utilizando el siguiente comando:

dotnet new blazorwasm -o MiAplicacionJWT

Ejemplo de Implementación

Paso 1: Crear el Proveedor de Autenticación

Crea un archivo llamado AuthenticationProvider.cs en tu proyecto Blazor. Este proveedor se encargará de manejar la autenticación utilizando JWT.

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.JSInterop;
using System.Security.Claims;
using System.Text.Json;

namespace MiAplicacionJWT
{
    public class AuthenticationProvider : AuthenticationStateProvider
    {
        private readonly IJSRuntime _jsRuntime;

        public AuthenticationProvider(IJSRuntime jsRuntime)
        {
            _jsRuntime = jsRuntime;
        }

        // Método para iniciar sesión
        public async Task Login(string token)
        {
            // Almacenar el token en el almacenamiento local
            await _jsRuntime.InvokeVoidAsync("localStorage.setItem", "jwt_token", token);

            // Notificar que el estado de autenticación ha cambiado
            var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt"));
            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(authenticatedUser)));
        }

        // Método para obtener el estado de autenticación
        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            var token = await _jsRuntime.InvokeAsync<string>("localStorage.getItem", "jwt_token");
            var identity = string.IsNullOrEmpty(token) ? new ClaimsIdentity() : new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt");

            var user = new ClaimsPrincipal(identity);
            return new AuthenticationState(user);
        }

        // Método para analizar claims del JWT
        private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
        {
            var claims = new List<Claim>();
            var payload = jwt.Split('.')[1];
            var payloadJsonBytes = Base64UrlEncoder.Decode(payload);
            var payloadJson = JsonDocument.Parse(payloadJsonBytes);

            foreach (var property in payloadJson.RootElement.EnumerateObject())
            {
                claims.Add(new Claim(property.Name, property.Value.ToString()));
            }

            return claims;
        }
    }
}

Paso 2: Configurar el Servicio de Autenticación

En el archivo Program.cs, registra el proveedor de autenticación.

using Microsoft.AspNetCore.Components.Authorization;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");

// Registrar el proveedor de autenticación
builder.Services.AddScoped<AuthenticationStateProvider, AuthenticationProvider>();

await builder.Build().RunAsync();

Paso 3: Implementar el Componente de Inicio de Sesión

Crea un nuevo componente llamado Login.razor para manejar el inicio de sesión del usuario.

@page "/login"
@inject AuthenticationProvider AuthProvider
@inject HttpClient Http

<h3>Iniciar Sesión</h3>

<input @bind="username" placeholder="Nombre de usuario" />
<input @bind="password" type="password" placeholder="Contraseña" />
<button @onclick="Login">Iniciar Sesión</button>

@code {
    private string username;
    private string password;

    private async Task Login()
    {
        // Realizar la solicitud al servidor para autenticar al usuario
        var response = await Http.PostAsJsonAsync("https://tu-api.com/auth/login", new { username, password });

        if (response.IsSuccessStatusCode)
        {
            var token = await response.Content.ReadAsStringAsync();
            await AuthProvider.Login(token);
            // Redirigir a la página principal
            NavigationManager.NavigateTo("/");
        }
        else
        {
            // Manejar errores de autenticación
            Console.WriteLine("Error de inicio de sesión.");
        }
    }
}

Paso 4: Proteger las Rutas

Para proteger las rutas de tu aplicación, utiliza la directiva [Authorize] en los componentes que deseas restringir.

@page "/protected"
@attribute [Authorize]
<h3>Página Protegida</h3>
<p>Solo usuarios autenticados pueden ver este contenido.</p>

Conclusión

Hemos visto cómo integrar JWT en una aplicación Blazor WebAssembly, desde la creación del proveedor de autenticación hasta el manejo del inicio de sesión del usuario. Esta configuración permite una gestión eficiente de la autenticación y autorización, lo que mejora la seguridad de la aplicación.

Referencias