El sistema de autenticación y autorización conocido como ASP.NET Membership se introdujo en 2005, cuando vió la luz ASP.NET 2.0 y desde entonces ha habido muchos cambios en las formas en que las aplicaciones web manejan la autenticación y la autorización.
ASP.NET Identity es el nuevo sistema de autenticación y autorización, incluído en las plantillas que trae Visual Studio 2013 para los proyectos del tipo ASP.NET MVC, Web Forms, Web API y SPA, para construir modernas aplicaciones para la web, teléfonos o tablets.

Un poco de historia sobre los sistemas de Autorización/Autenticación en ASP.NET

1 . ASP.NET Membership:
Como mencionamos en la introducción, este fue el primer sistema de Autorización/Autenticación presente en ASP.NET y fue diseñado para resolver los requisitos comunes en el año 2005, que involucraban la autenticación de formularios, y el uso de una base de datos SQL Server para guardar los nombres de usuario, contraseñas y datos de perfil.
Hoy en día existe una gama mucho más amplia de opciones de almacenamiento de datos para las aplicaciones web, y la mayoría de los desarrolladores quieren permitir que sus sitios puedan usar los proveedores de identidad social (Facebook, Twitter, Google, etc), para autenticación y autorización. Entre las limitaciones que hacen esto dificil de lograr con ASP.NET Membership, podemos mencionar:

  • El esquema de base de datos fue diseñado para SQL Server y no es posible cambiarlo. Podemos agregar información de perfil, pero los datos adicionales se agregan en una tabla diferente, lo que hace difícil el acceso por cualquier medio, excepto a través de la API del proveedor de perfiles.

  • El proveedor del sistema está escrito para un sistema de base de datos Relacionales. Podríamos escribir un proveedor para almacenar información de suscripción en un mecanismo de almacenamiento no relacional, (por ejemplo tablas de Windows Azure Storage o una base de datos NoSQL, como por ejemplo MongoDB), pero luego se tendría que trabajar en torno al diseño relacional y por lo tanto tendríamos que escribir mucho código y se generarían un montón de excepciones System.NotImplementedException para los métodos que no aplican a las bases de datos NoSQL.

  • Dado que la funcionalidad log-in/log-out se basa en la autenticación de formularios, el sistema de suscripciones no puede utilizar OWIN.
    OWIN incluye componentes de middleware para la autenticación, incluyendo soporte para inicios de sesión que utilizan proveedores externos de identidad (como cuentas de Microsoft, Facebook, Google, Twitter), y nombres de usuarios que utilizan cuentas de organización de Active Directory local o Windows Azure Active Directory.
    OWIN también incluye soporte para OAuth 2.0, JWT y CORS.

2 . ASP.NET Simple Membership:
Fue desarrollado como un sistema de membresía para ASP.NET Web Pages. Fue lanzado con WebMatrix y el SP1 de Visual Studio 2010.
Su objetivo, era poder agregar más facilmente funcionalidad de Membresía a una aplicación de Web Pages.
Si bien, facilita personalizar la información de perfil de usuario, todavía comparte los otros problemas con ASP.NET Membership, y tiene las siguientes limitaciones:

  • Dificultad para guardar datos de membresía en una base de datos no relacional.

  • No se puede utilizar con OWIN.

  • No funciona bien con los proveedores existentes de ASP.NET Membership.

  • No es extensible.

3 . ASP.NET Universal Providers:
Fueron desarrollados para hacer posible persistir información de membresía en SQL Azure, y también trabajan con SQL Server Compact. Los ASP.NET Universal Providers se construyeron utilizando Entity Framework Code First, lo que significa que pueden usarse para guardar datos en cualquier almacén de datos que soporte EF.
Fueron construídos sobre la infraestructura de ASP.NET Membership, por lo que aún tienen las mismas limitaciones que el proveedor SqlMembership. Es decir:

  • Fueron diseñados para bases de datos relacionales y es difícil personalizar el perfil y la información del usuario.

  • Estos proveedores siguen utilizando la autenticación de formularios para la funcionalidad log-in and log-out.

Y finalmente... ASP.NET Identity

La suposición de que los usuarios iniciarán sesión introduciendo un nombre de usuario y una contraseña que previamente han registrado en su propia aplicación ya no es la única opción válida. La web se ha vuelto más social. Los usuarios interactúan entre sí en tiempo real a través de canales sociales como Facebook, Twitter y otros sitios web sociales. Los desarrolladores quieren que los usuarios puedan iniciar sesión con sus identidades sociales, para que puedan tener una experiencia rica en sus sitios web. Un moderno sistema de membresía, debe permitir iniciar sesión con la autenticación de proveedores como Facebook, Twitter, y otros.

Así como el desarrollo web ha evolucionado, también lo hicieron los patrones de desarrollo web. Las pruebas unitarias de código se convirtieron en una preocupación central para los desarrolladores de aplicaciones.
En 2009 ASP.NET agrega un nuevo framework basado en el patrón Modelo-Vista-Controlador (MVC), en parte para ayudar a los desarrolladores a crear aplicaciones ASP.NET testeables. Los desarrolladores que querían usar unit testing en la lógica de la aplicación también querían ser capaces de hacer lo mismo con el sistema de membresía.

Teniendo en cuenta estos cambios en el desarrollo de aplicaciones Web, ASP.NET Identity se desarrolló con los siguientes objetivos:

  • One ASP.NET Identity:

    • ASP.NET Identity puede usarse con todos los frameworks de ASP.NET, tales como ASP.NET MVC, Web Forms, Web Pages, Web API, SPA y SignalR.
    • ASP.NET Identity puede usarse cuando usted construye aplicaciones web, para celulares, windows store, o híbridas.

  • Facilidad para conectar datos de perfil de usuario:

    • Usted tiene control sobre el esquema de información de usuario y sobre el perfil. Por ejemplo, usted puede habilitar al sistema para almacenar facilmente las fechas de nacimiento entradas por los usuarios cuando registran una cuenta en la aplicación.

  • Control de Persistencia:

    • Por defecto, ASP.NET Identity almacena toda la información del usuario en una base de datos. ASP.NET Identity, utiliza Entity Framework Code First para implementar la totalidad de su mecanismo de persistencia.

    • Debido a que usted controla el esquema de la base de datos, las tareas comunes, como el cambio de nombres de las tablas o cambiar el tipo de datos de las llaves primarias es simple de hacer.

    • Es fácil conectarse a diferentes mecanismos de almacenamiento, como SharePoint, Windows Azure Storage Table Service, bases de datos NoSQL, etc, sin tener que tirar excepciones System.NotImplementedExceptions.

  • Pruebas Unitarias:

    • ASP.NET Identity convierte a las aplicaciones web en más testeables. Usted puede escribir pruebas unitarias para las partes de su aplicación web que usan ASP.NET Identity.

  • Proveedor de roles:

    • Hay un proveedor de roles que le permite restringir el acceso a partes de la aplicación basado en roles.
      Por ejemplo, usted puede crear fácilmente roles como "Admin" y agregar usuarios a los roles.

  • Basado en Notificaciones:

    • ASP.NET Identity admite la autenticación basada en notificaciones (claims-based authentication), donde la identidad del usuario se representa como un conjunto de notificaciones. Las notificaciones permiten a los desarrolladores ser mucho más expresivos para describir la identidad de un usuario de lo que permiten los roles. Mientras que la membresía por roles es sólo un valor lógico (miembro o no miembro), una notificación puede incluir información más rica acerca de la identidad de un usuario y su membresía.

  • Proveedores de Login Sociales:

    • Usted puede fácilmente añadir log-ins sociales como cuentas de Microsoft, Facebook, Twitter, Google y otros para su aplicación, y almacenar los datos específicos del usuario en la aplicación.

  • Windows Azure Active Directory:

    • También puede agregar la funcionalidad de acceder al sistema mediante Windows Azure Active Directory, y almacenar los datos específicos del usuario en la aplicación. Para más información, vea Métodos de Autenticación, más adelante en este mismo post.

  • Integración con OWIN:

    • La autenticación de ASP.NET ahora está basada en middlewares OWIN que se pueden utilizar en cualquier sistema basado en OWIN. ASP.NET Identity no tiene ninguna dependencia en System.Web, es un framework totalmente compatible con OWIN y se puede utilizar en cualquier aplicación alojada OWIN.

    • ASP.NET Identity usa OWIN Authentication para el log-in/log-out de los usuarios en el sitio web. Esto significa que en lugar de utilizar FormsAuthentication para generar la cookie, la aplicación utiliza OWIN CookieAuthentication para hacer eso.

  • Paquete Nuget:

    • Se redistribuye como un paquete NuGet que se instala en las aplicaciones Web a construir. Puede descargar este paquete NuGet de la galería NuGet.

    • Liberar ASP.NET Identity como un paquete NuGet, hace que sea más fácil para el equipo de ASP.NET iterar sobre las nuevas características y correcciones de errores, y entregarlos de una manera más ágil.

Métodos de Autenticación


Visual Studio 2013 ofrece varios métodos de autenticación para las plantillas para crear Web Forms, MVC, y Web API, como se ve en la siguiente imagen:

Autenticacion

  • No Authentication: Si selecciona esta opción, la aplicación no contendrá una página para acceder al sistema, tampoco ninguna interfaz de usuario que indique quién está conectado, ni clases de entidad para la base de datos de membresía, como tampoco una cadena de conexión para dicha base de datos (que no existirá).

  • Individual User Accounts: Si selecciona esta opción la aplicación se puede configurar para utilizar ASP.NET Identity para la autenticación de usuarios. ASP.NET Identity permite a un usuario registrar una cuenta, mediante la creación de un nombre de usuario y contraseña en el sitio o mediante la firma con los proveedores sociales como Facebook, Google, una cuenta de Microsoft, LinkedIn o Twitter. El almacén de datos predeterminado para perfiles de usuario es una base de datos SQL Server LocalDB, que se puede implementar en SQL Server o en una base de datos de SQL Azure para el sitio de producción.

  • Organizational Accounts: Si selecciona esta opción, la aplicación se puede configurar para utilizar Windows Identity Foundation (WIF) para la autenticación basada en cuentas de usuario en Azure Active Directory (AD Azure, que incluye Office 365) o Windows Server Active Directory.

  • Windows Authentication: si elije esta opción la aplicación de ejemplo se configura para utilizar el módulo de autenticación de Windows IIS. La aplicación mostrará el dominio y el ID de usuario de Active Directory o la cuenta de equipo local con la que se ha iniciado sesión en Windows, pero no incluirá registración de usuario o la opción log-in en la interfaz de usuario.
    Esta opción está pensada para los sitios web de intranet.
    Como alternativa, puede crear un sitio de Intranet que utiliza la autenticación AD, eligiendo la opción on-Premises en Organizational Accounts. Esta opción utiliza Windows Identity Foundation (WIF) en lugar del módulo de autenticación de Windows. Se requieren algunos pasos adicionales con el fin de establecer la opción On-Premises, pero WIF permite características que no están disponibles con el módulo de autenticación de Windows. Por ejemplo, con WIF puede configurar el acceso a aplicaciones en Active Directory y hacer consultas a los datos del directorio. En la siguiente imagen, se muestra esta opción:

On-Premises

Primeros Pasos con ASP.NET Identity

Como ya mencionamos, ASP.NET Identity se utiliza en las plantillas de proyectos de Visual Studio 2013 para ASP.NET MVC, Web Forms, Web API y SPA.
Para finalizar este post, vamos a ilustrar cómo estas plantillas de proyectos utilizan ASP.NET Identity para agregar funcionalidad para registrarse, iniciar sesión y cerrar la sesión de un usuario.
Pasos:

  1. Creamos una aplicación ASP.NET MVC con Individual Accounts y la llamamos MVC_IndividualAccounts, como vemos en las siguientes imágenes:

New Project

MVC

2 . El proyecto creado contiene los tres paquetes de ASP.NET Identity siguientes:

  • Microsoft.AspNet.Identity.EntityFramework:
    Este paquete tiene la implementación de Entity Framework de ASP.NET Identity que guardará tanto los datos como el esquema en una base de datos SQL Server.

  • Microsoft.AspNet.Identity.Core:
    Este paquete tiene las interfaces principales de ASP.NET Identity. Puede ser utilizado para escribir una aplicación de ASP.NET Identity que persista los datos en diferentes almacenes de datos, como Azure Storage Table, bases de datos NoSQL, etc.

  • Microsoft.AspNet.Identity.OWIN:
    Este paquete contiene la funcionalidad que se utiliza para conectar la autenticación OWIN con ASP.NET identity en aplicaciones ASP.NET. Esto se utiliza cuando usted agrega funcionalidad de log-in a su aplicación y llama al middleware OWIN autenticación para generar una cookie.

3 . Si observamos el archivo packages.config veremos que la plantilla que viene con Visual Studio 2013, instala varios paquetes pero que ya no son las últimas versiones de los mismos, como vemos en el siguiente código:

<?xml version="1.0" encoding="utf-8"?>
<packages>
   <package id="Antlr" version="3.4.1.9004" ... />
   <package id="bootstrap" version="3.0.0" ...  />
   <package id="EntityFramework" version="6.0.0" ...  />
   <package id="jQuery" version="1.10.2" ...  />
   <package id="jQuery.Validation" version="1.11.1" ... />
   <package id="Microsoft.AspNet.Identity.Core" version="1.0.0" ...  />
   <package id="Microsoft.AspNet.Identity.EntityFramework" version="1.0.0" ...  />
   <package id="Microsoft.AspNet.Identity.Owin" version="1.0.0" ... />
   <package id="Microsoft.AspNet.Mvc" version="5.0.0" ...  />
   <package id="Microsoft.AspNet.Razor" version="3.0.0" ...  />
   <package id="Microsoft.AspNet.Web.Optimization" version="1.1.1" ...  />
   <package id="Microsoft.AspNet.WebPages" version="3.0.0" ...  />
   <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.0.0" ...  />
   <package id="Microsoft.Owin" version="2.0.0" ...  />
   <package id="Microsoft.Owin.Host.SystemWeb" version="2.0.0" ...  />
   <package id="Microsoft.Owin.Security" version="2.0.0" ...  />
   <package id="Microsoft.Owin.Security.Cookies" version="2.0.0" ...  />
   <package id="Microsoft.Owin.Security.Facebook" version="2.0.0" ...  />
   <package id="Microsoft.Owin.Security.Google" version="2.0.0" ... />
   <package id="Microsoft.Owin.Security.MicrosoftAccount" version="2.0.0" ...  />
   <package id="Microsoft.Owin.Security.OAuth" version="2.0.0" ... />
   <package id="Microsoft.Owin.Security.Twitter" version="2.0.0" ... />
   <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" ... />
   <package id="Modernizr" version="2.6.2" ... />
   <package id="Newtonsoft.Json" version="5.0.6" ... />
   <package id="Owin" version="1.0" ... />
   <package id="Respond" version="1.2.0" ... />
   <package id="WebGrease" version="1.5.2" ... />
</packages>

4 . Ahora vamos a actualizar todos los paquetes, con Manage NuGet Packages for Solution, pulsando Updates y luego el botón Update All

Update ¨Packages

5 . Luego del proceso de actualización volvemos a abrir el archivo packages.config y veremos que en la mayoria de los paquetes, hemos actualizado la versión:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Antlr" version="3.5.0.2" ... />
  <package id="bootstrap" version="3.2.0" ... />
  <package id="EntityFramework" version="6.1.1" ... />
  <package id="jQuery" version="2.1.1" ... />
  <package id="jQuery.Validation" version="1.13.0" ... />
  <package id="Microsoft.AspNet.Identity.Core" version="2.0.1" ... />
  <package id="Microsoft.AspNet.Identity.EntityFramework" version="2.0.1" ... />
  <package id="Microsoft.AspNet.Identity.Owin" version="2.0.1" ... />
  <package id="Microsoft.AspNet.Mvc" version="5.2.0" ... />
  <package id="Microsoft.AspNet.Razor" version="3.2.0" ... />
  <package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" ... />
  <package id="Microsoft.AspNet.WebPages" version="3.2.0" ... />
  <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.0" ... />
  <package id="Microsoft.Owin" version="2.1.0" ... />
  <package id="Microsoft.Owin.Host.SystemWeb" version="2.1.0" ... />
  <package id="Microsoft.Owin.Security" version="2.1.0" ... />
  <package id="Microsoft.Owin.Security.Cookies" version="2.1.0" ... />
  <package id="Microsoft.Owin.Security.Facebook" version="2.1.0" ... />
  <package id="Microsoft.Owin.Security.Google" version="2.1.0" ... />
  <package id="Microsoft.Owin.Security.MicrosoftAccount" version="2.1.0" ... />
  <package id="Microsoft.Owin.Security.OAuth" version="2.1.0" ... />
  <package id="Microsoft.Owin.Security.Twitter" version="2.1.0" ... />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" ... />
  <package id="Modernizr" version="2.7.2" ... />
  <package id="Newtonsoft.Json" version="6.0.3" ... />
  <package id="Owin" version="1.0" ... />
  <package id="Respond" version="1.4.2" ... />
  <package id="WebGrease" version="1.6.0" ... />
  </packages>

6 . Podemos generar el visualizador de Paquetes como se ve en la siguiente imagen:

Package Visualizer

En la siguiente imagen vemos la parte del diagrama generado en donde se muestran los paquetes necesarios para la implementación de ASP.NET Identity:

Visualizador

7 . Lanzamos el programa y creamos un usuario, para lo que hacemos click en el link Register en la página inicial de la aplicación:

Register

La siguiente imagen muestra la página Register con la que ingresamos el nombre de usuario y la contraseña.

Register2

8 . Es bueno estudiar el diagrama de la clase AccountController, para observar todos sus miembros:

Controller

9 . Vemos que entre todos sus miembros, esta clase, define una propiedad de lectura AuthenticationManager, cuyo código es:

private IAuthenticationManager AuthenticationManager
{
    get
    {
        return HttpContext.GetOwinContext().Authentication;
    }
}

Esta propiedad será usada más adelante, cuando el sistema permita el acceso al usuario

10 . Luego de crear un usuario con su contraseña y de hacer click en el botón Register, la acción Register del controlador Account crea el usuario, llamando al API ASP.NET Identity, como vemos en el siguiente código resaltado:

Código1

11 . Si observamos el Modelo que ha generado el template, veremos que dentro de la carpeta Models, tenemos dos archivos: AccountViewModels.cs y IdentityModels.cs. Si abrimos este último archivo, veremos que dentro hay dos clases (como vemos en el siguiente código:

using Microsoft.AspNet.Identity.EntityFramework;

namespace MVC_IndividualAccounts.Models
{
    // You can add profile data for the user by adding more properties to 
    // your ApplicationUser class, please visit:
    // http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    {
    }

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
        : base("DefaultConnection")
        {
        }
    }
}

A . La clase ApplicationUser, deriva de la clase IdentityUser que está definida en el namespace Microsoft.AspNet.Identity.EntityFramework. Esta clase incluye varias propiedades como Id, Username, PasswordHash, y otras, heredadas de IdentityUser. Si queremos, podemos agregar aquí, propiedades adicionales para almacenar información de perfil adicional sobre un usuario (por ejemplo, la fecha de nacimiento, etc).

B . La clase ApplicationDbContext que hereda de IdentityDbContext<ApplicationUser>, es nuestro contexto y ya incluirá las propiedades Usuarios y Roles. Podríamos agregarle propiedades adicionales para almacenar películas, libros, cuentas, empleados, o lo que una aplicación necesite para resolver un problema.

Las dos líneas de código remarcadas arriba, (en el método Register), hacen lo siguiente:
La primera:

var user = new ApplicationUser()
              {
                  UserName = model.UserName
              };

simplemente crea un objeto user, instancia de la clase ApplicationUser, vista anteriormente, y asignándole a la propiedad UserName el nombre ingresado en la página Register.
La segunda línea:

var result = await UserManager.CreateAsync(user, model.Password);

llama al método asincrónico CreateAsync de la clase UserManager, pasándole el usuario creado en la línea anterior y la contraseña entrada en la página de Registración, espera a que se complete, y la guarda en la variable result que es un objeto del tipo IdentityResult.
Tanto la clase UserManager, como la IdentityResult, están definidas en el namespace Microsoft.AspNet.Identity

12 .Si el usuario fue exitosamente creado, automáticamente le es permitido el acceso, a través del método SignInAsync:

Código2

13 . El método SignInAsync es un método asincrónico, generado por el template. Debajo, vemos su código y en la línea resaltada, vemos que genera un objeto del tipo ClaimsIdentity, llamando al método CreateIdentityAsync de la clase UserManager. Dado que tanto ASP.NET Identity y OWIN Cookie Authentication son sistemas basados en notificaciones, el framework requiere que la aplicación genere un ClaimsIdentity para el usuario.
ClaimsIdentity tiene la información acerca de todas las notificaciones para el usuario, tales como a qué roles que pertenece. También, en esta etapa, puede agregar más notificaciones para el usuario:

Código 3

14 . El código resaltado debajo en el método SignInAsync autentica al usuario usando la propiedad AuthenticationManager de la cual hablamos en el punto 9. Esta propiedad es del tipo IAuthenticationManager definido en el paquete Microsoft.Owin.
Para permitir el acceso al usuario, llama al método SignIn, pasándole el objeto del tipo ClaimsIdentity que creamos arriba:

Código 4

15 . Hacemos click en el link Log off. Esto llama la acción LogOff en el controlador account. El código siguiente, muestra su lógica, y en resaltado, aparece la línea que llama al método SignOut de la popiedad AuthenticationManager, de la que ya hablamos en los puntos 9 y 14. (Esto es análogo al método FormsAuthentication.SignOut utilizado por el módulo FormsAuthentication en Web Forms):

Código 5

De esta manera hemos explicado cómo Visual Studio 2013, implementa ASP.NET Identity, para el tipo de Autorización llamado Individual User Accounts
En otros post, trataré de explicar los otros tipos de Autorización.

Acerca del Autor

respag

respag

Fanático de la programación y de San Lorenzo de Almagro. Argentino de nacimiento y panameño por adopción. Profesor de Matemáticas, autodidacta y docente de alma.