[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:

image

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)

image

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:

image

Si cambiamos los roles a “Users” y ejecutamos

[SecurityAttribute(new[] { "Users" })]

image

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.

9 comentarios en “[Patrones] Intercepción de llamadas a métodos (II) AOP”

  1. Gracias kiquenet,

    Voy a cerrar esta serie con un interceptor de Castle windsor para ver otro ejemplo que no sea con Unity y algo se hará 😉

    Muchas gracias por tu comment 😉

  2. Tengo una pregunta.¿No es esto identico a poner un atributo que ya tiene el framework para la autorizacion en metodos y clases con roles?

    [PrincipalPermission(SecurityAction.Demand, Role = “Administrators”)] protected void AccionSoloAdmins(parametros) {… }

    Me refiero a que la intercepcion con programacion orientada a aspectos es molon para las caracteristicas transversales de una aplicacion, pero justo para esto pienso que, o me estoy perdiendo algo que no comprendo o no es necesaria la AOP (a no ser que ademas de lanzar una excepcion se necesite mas codigo para hacer otras cosas).

  3. Hola Crowley,

    Quizás no he estado muy acertado con el ejemplo pero no quería complicarlo mucho y a lo mejor tendría que haber puesto un código de validación de seguridad distinto, pero…

    ¿Con [PrincipalPermission(SecurityAction.Demand, Role = “Administrators”)] como metes una validación más compleja?

    Con PostSharp puedes hacerlo, puedes meter el código que quieras a la entrada y salida del método 🙂 esto aplica también para log, trazas, auditar código…

    No se si me he explicado bien 🙂

    Un saludo

  4. Luis Ruiz, sorry pero yo estoy con Crowley. Hablar de validación compleja y algo declarativo como los atributos es dificil, sobre todo porque esto te ha quitado toda la flexbilidad del mundo en cuanto a cambio. Después de haber leido la serie de post que habéis puesto sinceramente creo que se está enrollando un poco el tema. A mi me gusta se simplista y se están mezclando varias cosas, una es la autenticación, para la cual tienes mecanismos para delegarla en terceros, otra la authorización para los cuales algo declarativo es poco flexible y generalmente con un nivel de granularidad muy alto, por no decir que invalida o hace imposible tomar distintos caminos en función de las atribuciones de una identidad.

    Unai

  5. Hola Unai,

    Y no te quito la razón, por eso digo que esta manera a mí personalmente no me gusta mucho y por eso me gusta más aa proximación con Interceptores.

    Entiendo que con lo delegar en terceros te refieres a WIF, no? Habra casos donde WIF sea genial. nosotros en SharePoint lo hemos utilizado, pero habrá casos donde no entre y a lo mejor estas soluciones caben mejor, no?

    Os agradezco los comentarios porque así se enriqueze uno 😉 pero la idea de la serie en general es ver un poco de todo y las posibilidades que tenemos.

    Un saludo y gracias.

  6. Además entiendo que por cada cosa se paga un precio, con Interceptores de IoC tendremos que pagar un coste de performance (Que en unos casos será asumible en otros no), con AOP, en este caso PostSharp nuestro código IL será modificado… pero vamos decía es mostrar que hay distintas maneras de hacer las cosas y luego que cada uno elija la que mas le convenga 🙂

    Un saludo

  7. OK Luis. Entonces es que no me estoy perdiendo nada y simplemente ha sido mala suerte escoger justo este ejemplo.
    Te has explicado muy bien y creo que al final estamos todos de acuerdo con que esta solucion no es la mas adecuada para una autorizacion basada en roles.

Deja un comentario

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