Ejemplos y Presentación del Run WebCamp – Acceso a Datos y Modelado con Entity Framework

por Daniel Laco  15. marzo 2011

 

Yá están publicados los ejemplos y la presentación de la charla que realizamos en el evento Run WebCamp con el compañero de ruta, Martín Salías.

Pueden encontrar los archivos en www.vemn.com.ar/conferencias

 

Tags: , , ,

ASP.NET | Entity Framework | General | Sharepoint

Seguridad y Autorizacion centralizada en base de datos con Asp.Net MVC

por Andres Stang  22. diciembre 2010

La palabra Seguridad es siempre una consulta que recibo cuando hablo de cómo programar en Asp.Net, y siempre me gusta dar el mismo chiste como respuesta: “Vamos por partes decía Jack el Destripador”. Es importante dividir un problema grande en problemas más pequeños y por ende más manejables, y hablando de seguridad la fórmula es sencilla.

 

SEGURIDAD = AUTENTICACIÓN + AUTORIZACIÓN


Es decir, tenes que resolver por un lado como identificar al usuario, para saber que es quien dice ser que es, y por el otro lado una vez que sepamos su identidad, tenemos que decidir si lo dejamos acceder o no.

Cuando creamos un proyecto nuevo de MVC, el template nos da una GRAN ayuda y propone resolver (mejor dicho, ya lo implementa y lo resuelve por defecto) cada tema con un componente específico. Para la autenticación utiliza Asp.Net Membership y para la autorización el decorador [Authorize].

Ambos componentes funcionan maravillosamente pero hay uno que me gusta y otro que no. Concretamente Asp.Net Membership me parece perfecto para resolver una gran cantidad de escenarios y contextos, y generalmente lo utilizo en mis proyectos. Pero el decorador de autorización a mi criterio tiene dos grandes falencias:

  • Falta de flexibilidad: el componente de autorización puede recibir como parámetro el usuario y el rol, pero esto queda explícito en el código, es decir, si me surge la necesidad de agregar un nuevo rol al sistema deberé recorrer el código, cambiarlo, recompilar y realizar un deploy del sitio.
  • Verborragico: el componente requiere gran escritura y definición por parte del programador. Esto, mas allá de la poca elegancia del código, define que sea el programador quien decide quien esté autorizado a entrar a cada acción. Y ante un error, descuido o falta de memoria del programador podemos comprometer a nuestra aplicación dejando expuesta funcionalidad sensible a usuarios indeseados.

 

¿Cómo resolvemos esto?


Allá por el año 2007 Daniel Laco escribió uno de los post más consultados de este sitio:


Autenticación de usuarios basada en Roles utilizando HTTPModules en ASP.NET


De forma muy sencilla y elegante resuelve las dos falencias presentadas. Y si bien el código no es compatible con todas las versiones del .net framework, o con el paradigma MVC, el concepto si aplica en el universo Asp.net.

Lo que haremos el día de hoy, es actualizar un poco el código para que puede ser utilizado en nuestros proyectos de MVC ;)

Lo primero que tenemos que hacer es programar el método de nuestro modulo, quedaría algo así:

 

 public void Init(HttpApplication context)
 {
     context.AuthorizeRequest += new EventHandler(OnAuthorizeRequest);
 }
 
 void OnAuthorizeRequest(object sender, EventArgs e)
 {
     HttpContext context = ((HttpApplication)sender).Context;
 
     RouteData routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(context));
 
     if (routeData != null)
     {
         string controller = routeData.GetRequiredString("controller");
         string action = routeData.GetRequiredString("action");
 
         if (!EstaAutorizado(controller, action, context.User))
         {
             /// 401 es el codigo de resultado HTTP para acceso no autorizado
             context.Response.StatusCode = 401; 
             context.Response.End();
         }
     }
 }

 

En el código vemos cómo recuperar la información de la ruta para saber que método estamos ejecutando, y luego definir que si no se encuentra autorizado el usuario, le responderemos con un código HTTP estándar: 401 (lista de códigos)

De esta forma dejamos actuar al framework de asp.net que ya tiene resuelto el enganche y resolución del caso. Por ejemplo, MVC viene configurado por defecto que ante un error de autenticación redirija al usuario automáticamente a la página de login:

 

<authentication mode="Forms">
   <forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>

 

Lo único que nos falta, es recordar agregar el modulo a nuestro web.config para que se ejecute:

<httpModules>
  <add name="MiModulo" type="AutorizacionMVCHttpModule.Models.MiModulo"/>
</httpModules>

 

Listo! Con muy pocas líneas hemos resuelto de manera elegante y limpia un requerimiento esencial y controversial en la mayoría de nuestros proyectos.

Les dejo el código fuente de ejemplo para que lo puedan descargar y ver implementado
Download AutorizacionMVCHttpModule.zip (262,77 kb)

Happy coding!

Tags: , , , , ,

.NET | ASP.NET | Desarrollo Web

Formulario Cabecera-Detalle en Asp.Net MVC con el default ModelBinder

por Andres Stang  30. marzo 2010

 

Descargar Codigo Fuente

Tal vez les suceda que alguna vez en su feliz programación de Asp.Net MVC quieren generar un formulario de entrada de datos que permita, sin los molestos tiempos de carga de postback, agregar N cantidad de elementos.

Es decir, generar un modelo de Cabecera-Detalle en el cliente, y luego poder leerlo del lado servidor utilizando solo MVC y Javascript. No, me refiero a SOLO MVC, es decir sin un ModelBinder personalizado, que sería la opción que primero nos viene a la mente gracias a la extensibilidad propuesta por el framework.

Podemos imaginarnos el siguiente ejemplo de modelo:

   1: public class Materia
   2: {
   3:     public int Codigo { get; set; }
   4:     
   5:     public string Nombre { get; set; }
   6:  
   7:     public List<Alumno> AlumnosInscriptos { get; set; }
   8: }

Supongamos que queremos permitir al usuario generar una nueva materia y asignarle alumnos a la misma desde una lista de selección. Para simplificar el alumno va a estar definido por:

   1: public class Alumno
   2: {
   3:     public int Matricula { get; set; }
   4:  
   5:     public string Nombre { get; set; }
   6: }

 

Entonces realizamos el siguiente formulario web:

 

En el mismo vamos a poder cargar las propiedades de la materia y mediante javascript permitiremos que se agreguen los alumnos al seleccionarlos del combo al presionar “Agregar”.

Pero… como hacemos luego para leer las propiedades de la materia y los N alumnos seleccionados del lado del servidor?

Muy fácil, utilizando el ModelBinder por defecto de MVC. Es decir, el framework ya viene preparado para este escenario, solo que (a mi apreciación) está poco documentado.

Es decir, en nuestro método de controlador solo tendremos que colocar la siguiente definición:

   1: [AcceptVerbs(HttpVerbs.Post)]
   2: public ActionResult Index(Materia nuevaMateria)
   3: {
   4:     // HACER ALGO CON LA NUEVA MATERIA
   5:  
   6:     ViewData["CantidadAlumnos"] = nuevaMateria.AlumnosInscriptos.Count;
   7:  
   8:     return View("Alumnos");
   9: }

Y automáticamente podemos leer la instancia de la clase Materia con sus alumnos relacionados.

Donde está el secreto???

Lo importante es que al generar las filas dinámicamente de la tabla de alumnos también generemos los inputs para los valores de los alumnos que vayamos agregando. Por ejemplo, al agregar la fila nueva también insertaremos dos inputs ocultos de html con los valores que requiere la clase Alumno, es decir Matricula y Nombre:

   1: <input type="hidden" value="22" name="AlumnosInscriptos[1].Matricula" 
   2:     id="AlumnosInscriptos[1].Matricula" />
   3: <input type="hidden" value="Pedro" name="AlumnosInscriptos[1].Nombre" 
   4:     id="AlumnosInscriptos[1].Nombre" />

Podemos observar la particularidad del nombre y id del tag, es decir, debemos llamarlos de la siguiente manera:

<NombrePropiedadPadre>[indice].<NombrePropiedadHijo>

O para nuestro ejemplo:

AlumnosInscriptos[0].Nombre

De esta manera, el ModelBinder interpretara que se trata un elemento perteneciente a nuestra colección y nos facilitara el trabajo.

 

 

Pongo a disposición el código fuente perteneciente al ejemplo de este post:

ListBinder.zip (264,49 kb)

Happy Programming!

Tags: ,

ASP.NET | Desarrollo Web

Que hay de nuevo en VS2010?

por Daniel Laco  4. marzo 2010

Ya se viene la liberación de la versión final de Visual Studio 2010 y .NET 4.0 y uno siempre quiere tener una vista rápida de los cambios, agregados, etc.

En http://msdn.microsoft.com/en-us/library/bb386063(VS.100).aspx pueden encontrar un listado de todos los temas nuevos de esta plataforma.

 

Tags: , , , ,

.NET | ADO.NET | ASP.NET | Entity Framework | Visual Studio | WCF | WinForms

La correcta elección de las KEYWORDS en SEO (Search Engine Optimization)

por Alejandra Federico  17. febrero 2010

A la hora de querer seleccionar cuáles son aquellas palabras claves que debemos utilizar, para que nuestro sitio web este posicionado entre los primeros en los resultados de una búsqueda, se nos hace realmente dificil.

Es por ello que aquí les dejo algunas herramientas que quizás les sirva de ayuda para la selección de las palabras claves:

  • http://www.keyworddiscovery.com/search.html Esta herramienta nos sirve permite descubrir las diferentes palabras que los usuarios están utilizando en los buscadores, relacionada con la palabra que escribimos
  • http://www.kwmap.net/  Es una herramienta gráfica que muestra las relaciones entre los término de búsqueda como un gráfico.
  • http://freekeywords.wordtracker.com/ Esta herramienta te dará una lista con al menos 100 palabras relacionada con las palabras que buscamos y, lo más importante es que lo hace en orden de importancia según la cantidad de veces buscada.
  • http://www.abakus-internet-marketing.de/tools/topword.htm Es una herramienta que analiza las palabras claves y frases de las palabras claves de un sitio. Nos puede servir para estudiar nuestro propio sitio.

 

Tags: , ,

ASP.NET | Desarrollo Web

Optimización de sitios webs con Sprites

por Daniel Laco  5. febrero 2010

Si bien es una técnica antigua, existe la posibilidad de utilizarla en páginas webs mediante el uso de CSS.

Esto nos permite reemplazar el uso de muchas imágenes en nuestro sitio, por una sola que contenga lo que necesitamos. Esto reduce mucho los request al sitio, con la consiguiente mejora en la carga de las páginas.

Aqui les dejo una recopilación de artículos (en Inglés) con explicaciones y ejemplos sencillos de está forma de pensar las páginas.

Creando fácilmente Sprites con CSS

http://cssglobe.com/post/3028/creating-easy-and-useful-css-sprites

Explicación de que son los Sprites

http://www.peachpit.com/articles/article.aspx?p=447210

El misterio de los Sprites de CSS, Tutoriales y Ejemplos

http://www.smashingmagazine.com/2009/04/27/the-mystery-of-css-sprites-techniques-tools-and-tutorials/

 

Tags: ,

ASP.NET | Desarrollo Web | Sharepoint

9 puntos para lograr posicionarse (SEO)

por Alejandra Federico  30. enero 2010


9 puntos para lograr posicionarse (seo)

 

El SEO (Search Engine Optimizer) consiste en aplicar diversas técnicas que tienden a lograr que los buscadores de internet sitúen nuestra página en una buena posición y categoría alta, para determinados términos y frases claves.

A la hora de querer posicionarnos primeros debemos tener en cuenta los siguientes puntos:

  • Para empezar debemos focalizarnos en el título. Es lo más importante, primero porque los buscadores le dan bastante importancia a las palabras del título (sobre todo google) y luego porque es lo primero que se ve en la página de resultados. Hay que redactar un título que contenga las palabras claves en las que queramos estar bien posicionados y que sea atractivo al usuario que ve el resultado de la búsqueda. Debemos evitar colocar artículos (el, la, un, una). No se recomienda que sea superior a 60 caracteres, debe poseer aproximadamente entre 4 a 6 palabras. Los buscadores le dan mucha importancia a las palabras en negrita y de mayor tamaño.
  • Otro punto a tener en cuenta son las palabras claves. Para poder aparecer en los buscadores es necesario que nos focalicemos en aquellas palabras por las cuales creemos que nos van a buscar. Estas palabras claves deben ir en los títulos, etiquetas alt de las imágenes, los metatags, las URLS de nuestra página y en los enlaces de otras web.
    Se deben medir la densidad de las palabras claves. La densidad es el ratio de apariciones de una palabra o frase clave en el total de palabras que componen un texto. Por ejemplo, para un texto de 200 palabras, si una palabra aparece 10 veces, su densidad será del 5%.
    La densidad de palabras clave es uno de los factores que tienen en cuenta los buscadores para ordenar los resultados de una búsqueda.
    Para poder chequear como se encuentra nuestro sitio con respecto a la densidad existen algunos programas que nos indican cuales son las palabras más relevantes que figuran en nuestra web: 
  • Nuestro sitio debe poseer contenido de calidad de esta manera vamos a lograr que otras web nos enlacen. El blog nos puede servir de gran utilidad para que otros realicen visitas. Como mínimo hay que publicar un artículo por mes. Un modo para poder mantenerlo es obtener de otro sitio algún artículo interesante y copiar el link de donde fue sacado.
  • Los enlaces funcionan como una especie de voto o adhesión a una web en particular. Si los enlaces son de calidad esa valoración será positiva, de lo contrario nos perjudicarán.
  • En las etiquetas se debe utilizar H1 H2 H3… El H1 es recomendable que haya uno sólo por página, H2
    y H3 se pueden repetir algunas veces, aunque siempre ubicados de forma
    correcta:

    H1 para el título
    H2 para el título de las entradas
    H3 para los comentarios y otras subcategorías
  • No se debe insertar contenido importante en pdf, medios gráficos o flash. El abuso de JavaScript y Flash dificulta que un buscador nos "entienda".
  • Participar en redes sociales, por ejemplo Linkedin, Facebook, Hi5, Orkut, y de esta manera poder obtener mas visitas a nuestro sitio web.
  • Se debe realizar un mapa del sitio (site map). Si no se tiene es conveniente confeccionar un mapa del sitio actual, que contenga todas las URL’s de la páginas publicadas, incluyendo sus títulos, descripciones, palabras clave, meta tag robots, fecha de última modificación y nivel o algún tipo de clasificación de importancia dentro del árbol.
  • Puntos que no hay que realizar para NO ser penalizados por los buscadores:
    1. Evitar utilizar textos ocultos
    2. Evitar utilizar enlaces ocultos.
    3. No cargar la página con palabras claves irrelevantes.
    4. No enviar consultas automatizadas a google.
    5. Venta y/o compra de enlaces con el sólo motivo de aumentar artificialmente el PageRank.
    6. Técnicas de alto riesgo como el cloaking (mostrar dos o más páginas diferentes según quien desee visualizarla, es decir, no enviar la misma página al usuario y al buscador).
    7. Páginas Doorway (páginas creadas con el propósito de posicionarse para una determinada palabra clave y, entonces, ser una página de entrada a la web alternativa) creadas masivamente o de contenido prácticamente idéntico.
    8. Enlaces entrantes, es decir, hacia nuestra web, en cantidad masiva desde weblogs, guestbooks o granjas de enlaces.
    9. Enlaces salientes, es decir, desde nuestra web, hacia sitios web que realizan prácticas de alto riesgo o SPAM.
    10. No crear varias páginas, subdominios o dominios que presenten básicamente contenido duplicado.

Como conclusión, en el posicionamiento juegan cientos de variables y algorítmos que cambian día a día. Por más que en determinados
momentos se logren excelentes resultados, nadie tiene la verdad. No es una ciencia cierta.

Tags: , ,

ASP.NET | Desarrollo Web

Excelente librería de gráficos de Barras, Curvas, etc. en Javascript

por Daniel Laco  13. enero 2010

No dejo de asombrarme con las cosas que desarrollan los programadores sobre javascript En http://www.highcharts.com/ se puede encontrar una impresionante libreria que permite generar gráficos de Torta, Barras, etc. para aplicaciones webs.

 

        

Tags: , ,

ASP.NET | JQuery | Javascript | Desarrollo Web

240 JQuery Plugins

por Daniel Laco  10. enero 2010

Tags: , ,

ASP.NET | JQuery | Javascript | Desarrollo Web

Autenticación de usuarios basada en Roles utilizando HTTPModules en ASP.NET

por Daniel Laco  23. septiembre 2007

Introducción   Código de Ejemplo HTTPMudules

Hoy en día, si hay algo crítico en todo sistema informático es el tema de la seguridad, particularmente en las aplicaciones Web, donde nos enfrentamos a una gran cantidad de ataques, de los mas diversos tipos.
Una de las necesidades más comunes en estos sistemas, además de los mecanismos propios de seguridad, es poder contar con un mecanismo de autorización basado en Roles o Perfiles, que permita al sistema verificar que roles tienen permiso a que recursos, que opciones de menú configurar o qué información mostrar en tiempo de ejecución.
En esta nota, explicaremos una implementación de este modelo de seguridad, utilizando la infraestructura que nos brinda ASP.NET, mediante la utilización de HttpModules, validando los Roles y Usuarios almacenados en una base de Datos.

Autenticación de usuarios por Roles

El trabajo con roles no es un tema nuevo en el desarrollo de aplicaciones, y hay distintas formas de implementarlo. Recuerdan cuando en ASP había que chequear la seguridad página por página?
Por supuesto que hay varias alternativas para tratar el mismo problema, algunas más eficientes y escalables que otras.
En ASP.NET esto está resuelto, ya que en el Web.Config se pueden configurar los accesos a las diferentes secciones de nuestra aplicación, por ejemplo, en la siguiente porción de código se indica que todos los usuarios tienen acceso a "página.aspx":

<location path="pagina.aspx">
    <system.web>
        <authorization>
            <allow users="*" />
        </authorization>
    </system.web>    
</location>

Pero, hay ocasiones en donde el escenario que se presenta es distinto, siendo necesario poder configurar dinámicamente el acceso a las páginas. Los usuarios, roles y páginas cambian continuamente por programación, en general, porque se almacenan en una base de datos, en un servicio de directorio como Active Directory o en alguna otra opción de almacenamiento.

Para atender a estos casos veremos una implementación de seguridad basada en HttpModules de ASP.NET, donde los roles (o perfiles) de los usuarios están almacenados en una base de datos, y la autorización es administrada con esta solución.

Primero debemos entender cómo funcionan y qué son estos HttpModules, para esto veamos el ciclo de vida de las páginas en ASP.NET y de qué modo interactúan estos módulos con el ciclo de vida de estas páginas :

El ciclo de una llamada en HTTP comienza en el IIS (Internet Information Server), continúa cuando la petición es enviada a aspnet_isapi.dll que es la que administra todo el flujo entre IIS y ASP.NET.
Cuando la petición ingresa en el circuito propiamente de ASP.NET, ésta pasa a través de los diferentes HttpModules configurados en la cadena, y por último la petición llega al HttpHandler.
Este HttpHandler se ocupará del armado de la página y realizará la escritura del Html hacia el IIS, que a su vez la retorna al navegador que realizó la petición original. (Ver figura 1):



Figura 1. Ciclo de vida de páginas ASP.NET

 

Dentro de este proceso, los HttpModules son filtros que se pueden programar e incluir en la configuración de la aplicación ASP.NET. Estos filtros permiten "atender" diferentes eventos que dispara ASP.NET durante el proceso de cada petición. Si miramos en el archivo machine.config de .NET veremos en la sección de HttpModules todos los filtros que vienen programados y configurados cuando se instala .NET, entre ellos están, por ejemplo, los que manejan las diferentes configuraciones de seguridad.

      <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />
      <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
      <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" />
…..
      <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" />

Programar un HttpModule es sencillo, solo requiere implementar la interfaz IHttpModule y desde el código definir en cuáles eventos se va a responder. Una vez que el componente está programado, solamente es necesario agregar la entrada correspondiente en el .config de la aplicación. Más adelante trataremos este punto con mayor claridad.
Si con .NET tenemos la posibilidad de poder "engancharnos" en el ciclo de vida de una página, es por de mas interesante que utilicemos esta funcionalidad para nuestra solución de seguridad basada en roles.
Veamos ahora el ejemplo para entender la solución:

Para comenzar tenemos una base de datos con los usuarios que acceden a nuestra aplicación, los roles de los mismos y las páginas del sistema.

Es decir, contaremos con una estructura mínima de 4 tablas, a saber:

  • Usuarios, que contiene todos los datos de los usuarios necesarios según las reglas del negocio de la aplicación y el identificador del rol al que pertenecen.
  • Perfiles, que contiene todos los perfiles que se utilizarán en la aplicación y una descripción de los mismos.
  • Paginas, que contiene todos los nombres y urls de las páginas del sistema.
  • PerfilesPaginas, que contiene todas las páginas que utiliza cada rol. 

 

 

Necesitamos además una clase que contenga la información del usuario y el componente que cumpla la función de HttpModule.
El método de autenticación estará basado en Forms. Ahora bien, de qué forma podemos tener información del usuario autenticado en cualquier punto de la aplicación? Una de las alternativas podría ser guardar información en la Session del usuario. En este ejemplo reemplazaremos directamente el Principal del HttpContext por una clase propia que implementa la interfaz IPrincipal, además de tener las propiedades propias de la interfaz, agregaremos métodos y propiedades útiles para nuestro modelo de seguridad.

Al personalizar este objeto a nuestras necesidades, nos quedará lo siguiente:

  • Principal: es un objeto que contiene información asociada al usuario actual, por ejemplo, su rol y su identidad, así como otros datos que puedan ser de interés según las reglas del negocio.
  • Identidad (Identity): representa al usuario, tiene distintas propiedades que permiten obtener diferentes datos de los usuarios, por ejemplo:
System.Security.Principal.IPrincipal user;
string username = user.Identity.Name ;

Nos permite obtener el nombre del usuario autenticado en nuestro sistema.

  • Roles o Perfiles: simplemente son los nombres de los distintos roles que se agregan al objeto principal, los mismos pueden encontrarse en la base de datos.
    public class FormsPrincipal :IPrincipal, IMyAppPrincipal
    {
        private IIdentity _identity;
        private string [] _roles;
        private string _Perfil;        
 
        public FormsPrincipal( IIdentity identity, string [] roles)
        {
            _identity = identity;
            _roles = roles;
            _Perfil = Perfil;
        }
        
        //...    
 
        //Propiedad que utilizaremos para saber si el usuario tiene o no habilitado
        //el acceso a una determinada página
        public bool IsPageEnabled(string pageName)
        {
            return Perfiles.IsPageEnabled( pageName, this._Perfil );  
        }
 
        //...    
    }

Cabe destacar que esta clase no esta completa, solo se reprodujo parcialmente, con el propósito de visualizar el objeto principal y como hemos implementado la interfaz IPrincipal.

El paso siguiente es configurar y programar la autenticación basada en Forms:
Agregamos la entrada en el web.config

<authentication mode="Forms"> 
    <forms loginUrl="Login.aspx" timeout="20"/>
</authentication>

Y programamos nuestra página Login.aspx, hemos agregado los comentarios correspondientes a los efectos de clarificar la funcionalidad de cada línea de programación:

private void btnSubmit_Click(object sender, System.EventArgs e)
{
    string user = txtUser.Text;
    string password = txtPassword.Text;
 
    //Chequeo de usuario y contraseña
    SeguridadEnAspNet.Usuario oUser = new SeguridadEnAspNet.Usuario();
    string perfil = oUser.GetPerfil(user, password);
 
    if (perfil.Length > 0) // perfil vacío significa que no fue encontrado
    {
        //Invoca a componente que se encarga del Cache de los datos
        //en este caso de las páginas a las que el perfil tiene acceso
        SeguridadEnAspNet.UserCache.AddPaginasToCache( perfil, SeguridadEnAspNet.Perfiles.GetPaginas(perfil) ,System.Web.HttpContext.Current ); 
        
        // Crea un ticket de Autenticación de forma manual, 
        // donde guardaremos información que nos interesa
        FormsAuthenticationTicket authTicket = 
                new FormsAuthenticationTicket(2,  // version
                user,
                DateTime.Now, 
                DateTime.Now.AddMinutes(60),
                false, 
                perfil, // guardo el perfil del usuario
                FormsAuthentication.FormsCookiePath);
        // Encripto el Ticket.
        string crypTicket = FormsAuthentication.Encrypt(authTicket);
            
        // Creo la Cookie
        HttpCookie authCookie = 
                new HttpCookie(FormsAuthentication.FormsCookieName,
                crypTicket);
 
        Response.Cookies.Add(authCookie); 
 
        // Redirecciono al Usuario - Importante!! no usar el RedirectFromLoginPage
        // Para que se puedan usar las Cookies de los HttpModules
        Response.Redirect( FormsAuthentication.GetRedirectUrl(user,false));
    }
    else
        // Muestro mensaje de error
        tblWarning.Style["display"] = "";
}

Solo hemos reproducido el código correspondiente al método del acceso, la clase completa la pueden ver en el código adjunto a la nota.

Veamos ahora la programación de nuestro HttpModule.

 
using System;
using System.Web;
using System.Security.Principal;
using System.Web.Security;
 
namespace SeguridadEnAspNet
{
    /// <summary>
    /// Modulo de Administración de la Seguridad 
    /// Seguridad basada en Forms
    /// </summary>
    public class CustomAuthenticationModule : IHttpModule
    {
        public CustomAuthenticationModule()
        {}
 
        /// <summary>
        /// Inicializa el HTTPModule y asigna los EventHandlers a cada Evento
        /// Esta es la parte donde se define a que eventos va a atender el HttpModule
        /// </summary>
        /// <param name="oHttpApp"></param>
        public void Init(HttpApplication oHttpApp)
        {
            // Se Registran los Manejadores de Evento que nos interesa
            oHttpApp.AuthorizeRequest += new EventHandler(this.AuthorizaRequest);
            oHttpApp.AuthenticateRequest += new EventHandler(this.AuthenticateRequest);
        }
 
        public void Dispose()
        {}
 
        /// <summary>
        /// Administra la autorización por Request
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AuthorizaRequest( object sender, EventArgs e)
        {    
            if (HttpContext.Current.User != null)
            {
                //Si el usuario esta Autenticado
                if (HttpContext.Current.User.Identity.IsAuthenticated)
                {
                    if (HttpContext.Current.User is MyApp.Seguridad.FormsPrincipal)
                    {
                        MyApp.Seguridad.FormsPrincipal principal = (SeguridadEnAspNet.FormsPrincipal) HttpContext.Current.User;
                        //Se verifica si el Perfil del usuario tiene autorización para acceder a la página
                        if( !principal.IsPageEnabled( HttpContext.Current.Request.Path) )
                            HttpContext.Current.Server.Transfer( "NoAutorizado.aspx"); 
                    }
                }
            }
        }
 
        /// <summary>
        /// Autentica en Cada Request
        /// </summary>
        /// <param name="sender">HttpApplication</param>
        /// <param name="e"></param>
        private void AuthenticateRequest(object sender, EventArgs e)
        {
            if (HttpContext.Current.User != null)
            {
                //Si el usuario esta Autenticado
                if (HttpContext.Current.User.Identity.IsAuthenticated)
                {
                    if (HttpContext.Current.User.Identity is FormsIdentity)
                    {
                        //Traigo el Rol que esta guardado en una Cookie encriptada
                        FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
                        FormsAuthenticationTicket ticket = id.Ticket;
 
                        string cookieName = System.Web.Security.FormsAuthentication.FormsCookieName;
 
                        string userData = System.Web.HttpContext.Current.Request.Cookies[cookieName].Value;
 
                        ticket  = FormsAuthentication.Decrypt(userData);
 
                        string rol="";
                        if( userData.Length > 0 )
                            rol= ticket.UserData;
 
                        //Se crea la clase Principal  y se asigna al CurrenUser del Contexto                                    
                        HttpContext.Current.User = new SeguridadEnAspNet.FormsPrincipal(_identity, perfil);                    
                    }
                }
            }
        }//AuthenticateRequest
        
    } //class
 
} //namespace

Una vez que tenemos nuestro módulo de seguridad (HttpModule: CustomAuthenticationModule), se deberá referenciar en el archivo de configuración de nuestra aplicación como se muestra a continuación:

<authentication mode="Forms"> 
    <forms loginUrl="Login.aspx" timeout="20"/>
</authentication>
<authorization>
    <deny users="?" />  
</authorization>
//…
<!-- Modulo de Autorización -->
<httpModules>
<add type="SeguridadEnAspNet.CustomAuthenticationModule,  name="CustomAuthenticationModule"/>
    SecurityModules"
</httpModules>

De esta forma estamos configurando el modo de autenticación por formularios, indicándole que la página de autenticación es "Login.aspx" y que los usuarios anónimos no tienen acceso a nuestra aplicación. También estamos definiendo el HttpModule que utilizaremos, en este caso, para administrar la seguridad de la aplicación.

Con esta configuración, ¿qué es lo que ocurre cuando un usuario realiza la petición de una página de nuestra aplicación?

Usuario No Autenticado
Si el usuario no está autenticado aún, realiza el proceso normal de autenticación por Formularios (Forms).

Usuario Autenticado
Si el usuario está autenticado, el primer evento que se dispara es el AuthenticateRequest, para obtener los roles (o perfiles) del usuario desde una cookie, y con esta información creamos la clase FormsPrincipal. Este objeto será posteriormente asignado al HttpContext.CurrentUser.
El evento que se dispara a continuación es el AuthorizaRequest. Lo que hace es verificar si el usuario tiene acceso a la página que está solicitando, en caso de que no este autorizado, la aplicación lo derivará a una página de error con el mensaje correspondiente.
Si bien la funcionalidad que estamos mostrando se aplica para páginas, también se puede extender a la clase que implementa IPrincipal y agregarle otros métodos que permita por ejemplo chequear a que datos de una página tiene acceso el rol. Para esto, en cualquier parte de nuestro código se puede hacer lo siguiente:

SeguridadEnAspNet.CustomPrincipal  user = (SeguridadEnAspNet.CustomPrincipal) HttpContent.CurrentUser;
    If( ! user.IsDataVisible("txtNombreControl") )
        txtNombreControl.Visible = false;

Conclusión:
Hemos visto como podemos hacer una administración de seguridad de una aplicación, mediante la utilización de código más eficiente y elegante. En el ejemplo mostrado con solo cambiar el HttpModule, se puede hacer que una aplicación pase de autenticar y autorizar desde una base de datos, a una autorización basada en Active Directory.
Si bien en este caso con los HttpModules presentamos un escenario de seguridad, es importante tener en cuenta que esta funcionalidad de poder interceptar los diferentes pasos por los que transita ASP.NET, puede aplicarse a un sin número de otros escenarios, sean de seguridad o no.

Se pueden bajar el código de la nota aquí Código de Ejemplo HTTPModules

Tags:

ASP.NET

Acerca de los Autores

Este es el blog del equipo de VEMN SA 
Presentaremos temas que nos parezcan de interés sobre tecnología .NET, Procesos y Metodologías y todo aquello relacionado con el proceso de desarrollo de Software

Month List

BlogRoll

Download OPML file OPML