[Patrones] Intercepción de llamadas a métodos (II) AOP
Continuando con la serie de posts sobre la intercepción de llamadas a métodos (Aquí está el primero) hoy le toca el turno a la programación orientada a aspectos, y ya que la seguridad se trata como un aspecto transversal (CrossCutting) a toda la aplicación (Como también los son los logs, las trazas…) vamos a ver como podemos hacer el ejemplo anterior usando AOP y en concreto usando la librería PostSharp (en este post no vamos a entrar en como PostSharp funciona, en el enlace tenéis mucha información y ejemplos)
Para descagar PostSharp podéis utilizar NuGet:

Una vez instalado, vamos a crear el atributo con el que aplicaremos la seguridad a los métodos que queramos. Para ello creamos una clase llamada SecurityAttribute, la marcamos como Serializable (Sino al compilar recibiremos un error)

y heredamos de OnMethodBoundaryAspect para convertir nuestra clase en un aspecto y que PostSharp lo interprete como tal
[Serializable]
public sealed class SecurityAttribute : OnMethodBoundaryAspect
{
private readonly string[] _roles;
public SecurityAttribute(string [] roles)
{
if (roles == null)
throw new ArgumentNullException("roles");
_roles = roles;
}
public override void OnEntry(MethodExecutionArgs args)
{
var windowsIdentity = WindowsIdentity.GetCurrent();
var windowsPrincipal = new WindowsPrincipal(windowsIdentity);
var allowed = _roles.Any(windowsPrincipal.IsInRole);
if (!allowed)
{
throw new SecurityException("No tiene permisos suficientes!");
}
base.OnEntry(args);
}
}
Lo que hacemos es crear un constructor parametrizado para pasarle los roles que podrán ejecutar el método e implementamos el Advice (La traducción sería consejo pero no suena nada bien ¿verdad?) que son notiifcaciones para cuando entramos y salimos del método y que implementan la funcionalidad de nuestro servicio, en este caso uso el evento OnEntry para comprobar la seguridad cuando se entra en el método.
He modificado el tema de la seguridad a Windows para que lo podáis probarlo en vuestra máquina, si cambiáis el rol a “Administrators o Users” si tenéis el SO en inglés o “Administradores o Usuarios” si está en español, veréis que el código se ejecuta sin lanzar la excepción.
Aplicamos el atributo al método Save del repositorio de SQL Server o al método Submit del servicio:
[SecurityAttribute(new[] { "Contributors" })]
public override void Save(Order order)
{
using (var connection = new SqlConnection())
{
// Save to SQL Server database
}
}
[SecurityAttribute(new[] { "Contributors" })]
public void Submit(Order order)
{
_orderRepository.Save(order);
}
Y ejecutamos la aplicación de consola, nos saltará la excepción de seguridad y podremos ver el mensaje:

Si cambiamos los roles a “Users” y ejecutamos
[SecurityAttribute(new[] { "Users" })]

Ya no recibimos el error!!!
Como se puede observar, es una solución más elegante que la que usamos con el patrón Decorator pero a mí me sigue sin gustar eso de tener que estar declarando atributos en los métodos, clases, propiedades… aunque es verdad que ya no tenemos que repetir tanto código, pero seguimos teniendo que mantener muchos atributos dispersos por todo nuestro código, me gusta más la idea de tener un único punto donde aplicar la seguridad y además poder basarlo en un sistema de reglas que leamos por ejemplo de una base de datos, xml…
Todo esto lo veremos en el siguiente y último post de la serie.
Un saludo y espero que os haya gustado.