0

Microsoft Orleans #07: Seguridad y Autenticación

En esta clase aprenderemos cómo proteger Orleans con autenticación y autorización, utilizando tokens JWT y filtros de seguridad para controlar el acceso a los Granos.

Objetivos de la Clase

  • Comprender cómo Orleans maneja la seguridad y autenticación.
  • Implementar tokens JWT en Orleans.
  • Proteger Granos con autorización.
  • Configurar interceptores de seguridad.
  • Probar el acceso restringido a Granos Orleans.

¿Cómo Orleans Maneja la Seguridad?

Por defecto, Orleans no implementa autenticación ni autorización. Sin embargo, podemos agregar seguridad utilizando:

  1. Tokens JWT para autenticar usuarios.
  2. Interceptors (IIncomingGrainCallFilter) para validar accesos.
  3. Restricciones en la API REST si Orleans se usa con ASP.NET Core.

En este ejemplo, implementaremos autenticación con JWT y validaremos accesos con filtros de seguridad en los Granos.

Implementar Seguridad con JWT en Orleans

1. Instalar Dependencias

Ejecuta en OrleansDemo:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package System.IdentityModel.Tokens.Jwt

2. Crear un Servicio de Autenticación

Crea JwtAuthService.cs en la carpeta Servicios:

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;

public static class JwtAuthService
{
    private const string SecretKey = "ClaveSuperSecreta123!"; // Debe ser segura

    public static string GenerarToken(string usuario)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(ClaimTypes.Name, usuario),
            new Claim(ClaimTypes.Role, "Admin") // Ejemplo de rol
        };

        var token = new JwtSecurityToken(
            issuer: "orleans-demo",
            audience: "orleans-users",
            claims: claims,
            expires: DateTime.UtcNow.AddHours(1),
            signingCredentials: credentials
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }

    public static ClaimsPrincipal ValidarToken(string token)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.UTF8.GetBytes(SecretKey);

        var validationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = "orleans-demo",
            ValidateAudience = true,
            ValidAudience = "orleans-users",
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateLifetime = true
        };

        try
        {
            return tokenHandler.ValidateToken(token, validationParameters, out _);
        }
        catch
        {
            return null;
        }
    }
}

Explicación del Código

  • GenerarToken(usuario): Crea un token JWT con nombre de usuario y rol.
  • ValidarToken(token): Verifica si el token es válido y devuelve los claims del usuario.

Implementar Seguridad en Granos Orleans

1. Definir un Grano Protegido

Crea ISeguroGrain.cs en Granos:

using System.Threading.Tasks;
using Orleans;

public interface ISeguroGrain : IGrainWithGuidKey
{
    Task<string> AccederSeguro(string token);
}

2. Implementar el Grano Protegido

Crea SeguroGrain.cs en Granos:

using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Orleans;

public class SeguroGrain : Grain, ISeguroGrain
{
    public Task<string> AccederSeguro(string token)
    {
        var claimsPrincipal = JwtAuthService.ValidarToken(token);
        if (claimsPrincipal == null)
            return Task.FromResult("Acceso denegado: Token inválido");

        var usuario = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
        return Task.FromResult($"Acceso concedido a {usuario}");
    }
}

Explicación del Código

  • AccederSeguro(string token): Recibe un token JWT y valida su autenticidad.
  • Si el token es válido, retorna el nombre del usuario autenticado.

Aplicar Filtros de Seguridad en Orleans

Orleans permite interceptar llamadas a Granos con IIncomingGrainCallFilter.

1. Crear un Interceptor de Seguridad

Crea AuthFilter.cs en la carpeta Seguridad:

using System;
using System.Linq;
using System.Threading.Tasks;
using Orleans;
using Orleans.Runtime;

public class AuthFilter : IIncomingGrainCallFilter
{
    public async Task Invoke(IIncomingGrainCallContext context)
    {
        if (context.InterfaceMethod.Name == "AccederSeguro")
        {
            var token = context.Arguments[0] as string;
            var claimsPrincipal = JwtAuthService.ValidarToken(token);

            if (claimsPrincipal == null)
            {
                throw new UnauthorizedAccessException("Acceso denegado.");
            }
        }

        await context.Invoke();
    }
}

Explicación del Código

  • Intercepta llamadas al método AccederSeguro().
  • Si el token es inválido, bloquea el acceso.

2. Registrar el Interceptor en el Silo

Edita Program.cs en OrleansDemo:

builder.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(SeguroGrain).Assembly).WithReferences());
builder.ConfigureServices(services => services.AddSingleton<IIncomingGrainCallFilter, AuthFilter>());

Probar Seguridad en Orleans

Paso 1: Iniciar el Silo

Ejecuta OrleansDemo.

Paso 2: Generar un Token JWT

Edita Program.cs en OrleansClient y agrega:

string token = JwtAuthService.GenerarToken("Carlos");
Console.WriteLine($"Token generado: {token}");

Paso 3: Llamar al Grano Protegido

var seguroGrain = client.GetGrain<ISeguroGrain>(Guid.NewGuid());
string respuesta = await seguroGrain.AccederSeguro(token);
Console.WriteLine(respuesta);

Salida esperada

Token generado: eyJhbGciOiJIUzI1...
Acceso concedido a Carlos

Si se usa un token inválido, la respuesta será:

Acceso denegado: Token inválido

Cuestionario de Autoevaluación

  1. ¿Qué es un token JWT y cómo se usa en Orleans?
  2. ¿Cómo Orleans maneja la seguridad de acceso a los Granos?
  3. ¿Qué hace un IIncomingGrainCallFilter en Orleans?
  4. ¿Cómo se genera y valida un token JWT en C#?
  5. ¿Qué sucede si un usuario intenta acceder a un Grano sin un token válido?

Resumen de la Clase

  • Implementamos autenticación en Orleans con JWT.
  • Creamos un Grano Protegido que verifica tokens antes de permitir el acceso.
  • Usamos filtros de seguridad (IIncomingGrainCallFilter) para restringir accesos.
  • Probamos el sistema generando un token JWT válido y verificamos que solo los usuarios autenticados pueden acceder a los Granos.

Próxima Clase: Implementación de Microservicios

En la siguiente clase, aprenderemos cómo usar Orleans en una arquitectura de microservicios y exponer sus Granos mediante APIs REST en ASP.NET Core.

Fernando Sonego

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *