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:
- Tokens JWT para autenticar usuarios.
- Interceptors (
IIncomingGrainCallFilter
) para validar accesos. - 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
- ¿Qué es un token JWT y cómo se usa en Orleans?
- ¿Cómo Orleans maneja la seguridad de acceso a los Granos?
- ¿Qué hace un
IIncomingGrainCallFilter
en Orleans? - ¿Cómo se genera y valida un token JWT en C#?
- ¿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.