Compartir a través de


Tecnología de vanguardia

Autenticación social en ASP.NET MVC 4

Dino Esposito

Dino EspositoSegún mi experiencia, la mayoría de los sitios web que tienen que autenticar usuarios lo hacen por medio de puertas de enlace de autenticación social. En este contexto, una puerta de enlace de autenticación social es solamente la plataforma de autenticación expuesta públicamente por las redes sociales como Twitter y Facebook. Si pensamos en los inicios de ASP.NET, no podemos evitar ver algunos parecidos entre la idea detrás de la iniciativa Passport y las puertas de enlace de autenticación social de hoy. Claramente no es lo mismo, pero en ambos casos se puede reconocer el objetivo de facilitar la vida de los usuarios al reducir la cantidad de credenciales que estos deben conservar.

El uso de un mismo conjunto de credenciales tiene sus ventajas y desventajas. Por un lado, baja la barrera de seguridad en torno a la privacidad. Al usar siempre el mismo nombre de usuario y contraseña, los hackers cuentan con más tiempo para adivinar nuestros secretos; y si lo logran, exponemos mucha más información. Por otro lado, sin embargo, al usar las mismas credenciales una y otra vez, podemos conectarnos con mayor facilidad y probar servicios nuevos. Esto es fantástico para los propietarios de los servicios, ya que así el número de usuarios crece más rápido, lo que significa que el servicio cuenta con más oportunidades de tener éxito.

En resumen, cada vez son más los sitios web que apuntan a atraer a una gran cantidad de usuarios y que actualmente ofrecen la opción doble de registrarnos con nuestras propias credenciales o mediante una puerta de enlace de autenticación para redes sociales. La tendencia es tan interesante que en la última versión de ASP.NET MVC 4 encontramos un marco de trabajo ad hoc para autenticar a los usuarios a través de varias redes sociales. En este artículo revisaré el código que obtenemos de la plantilla de proyecto de ASP.NET MVC 4. Las puertas de enlace de autenticación social usan el protocolo de autenticación abierta (OAuth), que es un protocolo bastante verboso. Por lo tanto, el código resultante no es exactamente trivial y podría requerir de más explicaciones.

La forma más rápida de autenticación MVC

ASP.NET MVC nos ofrece la oportunidad de comenzar a codificar a partir de una plantilla de código que ya incluye la autenticación. La plantilla de Aplicación de Internet que obtenemos con ASP.NET MVC 4 extiende las funciones a las puertas de enlace sociales. Supongamos, entonces, que tenemos un nuevo proyecto de Aplicación de Internet. En la primera compilación del código no pasa nada especial. La página en la Figura 1 nos informa que no se habilitó ningún servicio de autenticación externa aún.

The ASP.NET MVC 4 Template When No External Authentication Service Is ConfiguredFigura 1 Plantilla ASP.NET MVC 4, cuando no se configuró ningún servicio de autenticación externa

Para habilitar cualquiera de los servicios compatibles, solo debemos realizar algunos cambios pequeños en el archivo del código subyacente global.asax. En ASP.NET MVC 4, se recomienda que los proyectos incluyan una carpeta App_Start con clases xxxConfig que realicen las tareas de inicialización. Esas clases son simples contenedores de métodos estáticos que organizan mejor el código de arranque de la aplicación. He aquí una instantánea:

protected void Application_Start()
{  ...  AuthConfig.RegisterAuth();}

El método RegisterAuth contiene el código que permite que los usuarios inicien sesión con sus cuentas de otros sitios, como Facebook y Twitter:

public static class AuthConfig
{
public static void RegisterAuth()
  {
    OAuthWebSecurity.RegisterTwitterClient(
      consumerKey: yourTwitterAppKey
      consumerSecret: yourTwitterAppSecret);
    OAuthWebSecurity.RegisterFacebookClient(
      appId: yourFacebookAppKey,
    appSecret: yourFacebookAppSecret);
  }
}

La clase OAuthWebSecurity proviene del marco Web Pages y se encuentra dentro del espacio de nombres Microsoft.Web.WebPages.OAuth. Esta clase concluye la funcionalidad principal del protocolo OAuth, tal como se implementó en la biblioteca DotNetOpenAuth (DNOA) (consultar dotnetopenauth.net).

Para autenticar a los usuarios mediante una red social, primero debemos crear una aplicación dentro de la red social. Por lo tanto, necesitamos una aplicación para Twitter y una para Facebook, para autenticar a los usuarios mediante Twitter y Facebook dentro del sitio. Lo más probable es que creemos una aplicación para Twitter y Facebook con el mismo nombre del sitio y luego la configuremos para vincularla al sitio web. Lo que acabamos de llamar una aplicación para Twitter o Facebook no es en realidad una aplicación completa; además tiene un token de desarrollador especial para acceder desde el programa a Twitter, Facebook y otras redes sociales. Traté este aspecto en forma exhaustiva en las entregas pasadas de esta columna dedicada a la programación de Facebook. Para propósitos de este artículo, una aplicación para Twitter o Facebook consiste de un par de cadenas, una conocida como la llave y la otra como el secreto. La clave y el secreto se asocian de manera única con la aplicación social. Para inicializar OAuthWebSecurity, pasamos la clave y el secreto de cada red social que deseamos habilitar.

Al agregar llamadas a RegisterTwitterClient y RegisterFacebookClient, la interfaz de usuario del proyecto de ejemplo cambia y muestra estas opciones de registro en forma de botón. Si un usuario hace clic en el botón de Iniciar sesión, se le redirigirá al sitio de Twitter o Facebook, para que continúe con la autenticación. Si todo funciona bien, se le redirigirá al sitio original y ASP.NET lo reconocerá como un usuario autenticado.

Parece sencillo, ¿no es cierto? Bueno, hay muchos detalles importantes ocultos.

La ruta de OAuth hacia la autenticación

Cuando el usuario hace clic en el botón de Twitter, el sitio navega a Account/ExternalLogin. Veamos el código del método (el código se ubica en el archivo AccountController.cs):

public ActionResult ExternalLogin(String provider, 
  String returnUrl)
{
  return new ExternalLoginResult(provider,
    Url.Action("ExternalLoginCallback",
    new { ReturnUrl = returnUrl }));
}

La clase ExternalLoginResult es un tipo de contenedor para el siguiente código, que es el encargado de ponerse en contacto con la puerta de enlace de autenticación:

OAuthWebSecurity.RequestAuthentication(Provider, ReturnUrl);

La clase ExternalLoginResult es una clase auxiliar que también se encuentra en el archivo AccountController.cs. Debe tener en cuenta que en el código de la plantilla de proyecto, el nombre del proveedor se resuelve al mirar el atributo de nombre del botón:

    <button type="submit"
      name="provider"
      value="@p.AuthenticationClient.ProviderName"
      title="Log in using your @p.DisplayName account">
      @p.DisplayName
    </button>

Al final, el método RequestAuthentication recibe el nombre del proveedor de autenticación (Twitter, Facebook o cualquiera de los otros proveedores compatibles) y la URL que se va a devolver. De manera predeterminada, OAuthWebSecurity es compatible con los siguientes proveedores: Twitter, Facebook, LinkedIn, Google, Microsoft y Yahoo. Internamente, el método usa la biblioteca DNOA para llevar a cabo la tarea. Veamos lo que sucede si el usuario opta por realizar la autenticación a través de Twitter.

Como primer paso, la página predeterminada de autenticación de Twitter aparece frente al usuario. La página contiene el nombre de la aplicación de Twitter que realiza la tarea. En el ejemplo que se muestra en la Figura 2 es tFun. Al configurar una aplicación para Twitter, también señalamos los permisos que el usuario debe conceder a la aplicación al iniciar sesión. Al configurar la aplicación social de manera adecuada, podemos otorgarle al sitio web ASP.NET el permiso necesario para seguir a los nuevos usuarios o para publicar en nombre del usuario conectado. Este no es el caso de la aplicación de ejemplo. 

Authenticating via Twitter
Figura 2 Autenticación a través de Twitter

Si el usuario escribe las credenciales que Twitter (o la red social elegida) reconoce como válidas, el sitio de Twitter se redirige a la URL de devolución. El siguiente método con el que volvemos a adquirir el control después de la autenticación es ExternalLoginCallback. Lo que sabemos hasta ahora es que el usuario que intenta acceder a la aplicación se reconoció correctamente como un usuario de Twitter. No sabemos nada sobre él, ni siquiera el nombre de usuario. Me cuesta imaginar una aplicación que necesite usuarios autenticados y que pueda prescindir del nombre de usuario o de la dirección de correo electrónico. Después del paso de autenticación, la aplicación solo recibe un código, pero todavía no tiene permiso para acceder a la API de Twitter desde el programa. Para que esto ocurra, el código que se recibió en esta etapa se debe intercambiar por un token de acceso (por lo general tiene una duración limitada para evitar los usos indebidos). Este es el propósito de la llamada al método VerifyAuthentication que se encuentra en el cuerpo de ExternalLoginCallback. El objeto AuthenticationResult que recibimos de VerifyAuthentication contiene información sobre el usuario. La información real que obtenemos puede depender del proveedor, pero generalmente contiene al menos el nombre de usuario.

De la autenticación a la pertenencia

La autenticación del usuario es solo el primer paso. A continuación, tenemos que rastrear el usuario por nombre dentro del sitio. En un sistema de pertenencia de ASP.NET clásico, primero presentamos un formulario de inicio de sesión, validamos las credenciales y luego creamos una cookie de autenticación con el nombre de usuario y, opcionalmente, otra información clave. Twitter o Facebook nos ahorran la molestia de tener que estructurar un formulario de inicio de sesión y de validar las credenciales, además de la carga de tener que administrar y almacenar cuentas con información confidencial, como las contraseñas.

Pero, en definitiva, casi cualquier aplicación que requiera de usuarios autenticados también necesita un sistema de pertenencia, donde se mantiene un registro de cada usuario habitual por nombre. La responsabilidad de la creación de un sistema así sigue estando en nuestras manos. La plantilla ASP.NET MVC 4 sale al rescate, al ofrecer un paso extra, que automáticamente le da la oportunidad al usuario de escribir su nombre para mostrar, el que después se guarda en una tabla de pertenencia local. Esto es necesario solo la primera vez que el usuario inicia sesión en un sitio dado. En otras palabras, el formulario que se muestra en la Figura 3 sirve para el registro y el primer inicio de sesión.

First Login and the Complete Registration to the Site
Figura 3 Primer inicio de sesión y completar registro en el sitio

El nombre que se escribe en esta etapa se usa para crear la cookie de autenticación de ASP.NET, lo que finalmente cierra el círculo. Usamos Twitter para comprobar las credenciales, le pedimos al usuario que escriba el nombre para mostrar y creamos una cookie de autenticación normal. De ahora en adelante, todo funciona como de costumbre en ASP.NET para los sitios sujetos a la autenticación.

La plantilla de proyecto ASP.NET MVC 4 predeterminada guarda los datos de usuario en una base de datos .mdf local, que se crea en la carpeta App_Data. La tabla se administra con la API de pertenencia simple que se heredó del marco Web Pages.

El siguiente código muestra cómo la plantilla del proyecto de ejemplo obtiene el nombre para mostrar de la página de la Figura 3:

var loginData = OAuthWebSecurity.SerializeProviderUserId(
  result.Provider, result.ProviderUserId);
var name = OAuthWebSecurity
  .GetOAuthClientData(result.Provider)
  .DisplayName;
  return View("ExternalLoginConfirmation",
  new RegisterExternalLoginModel {
    UserName = result.UserName,
    ExternalLoginData = loginData
  });

La llamada a GetOAuthClientData es donde accedemos a cualquier información que el proveedor de Twitter comparte sobre el usuario que inició sesión. En el método ExternalLoginConfirmation ocurren dos cosas claves, que se resumen en el siguiente código:

OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);

La primera línea establece el registro nuevo en la base de datos local de pertenencia para la aplicación. La segunda línea es la que crea la cookie de autenticación. La plantilla predeterminada permite varias tablas de base de datos, como UserProfiles y webPages_OAuth­Membership. La última tabla almacena un registro con el nombre del proveedor (es decir, Twitter), el identificador único del proveedor para el usuario y un puntero a un identificador interno que identifica al usuario en la tabla UserProfiles, con el nombre para mostrar que el usuario mismo eligió en la página que se muestra en la Figura 3

Consideraciones finales

El protocolo OAuth administra la interacción entre un proveedor y una aplicación cliente. Twitter, Facebook y algunas otras redes sociales populares exponen sus API mediante OAuth. Una aplicación cliente puede usar la API de Twitter para dos propósitos principales: la simple autenticación de usuario y la operación con el proveedor a nombre del usuario y con su consentimiento. En ambos casos, la aplicación cliente debe iniciar sesión en el proveedor y obtener un token de acceso. El token de acceso tiene una validez limitada en el tiempo (pero se puede actualizar desde el programa) y solo tiene permiso para realizar las operaciones que el usuario final aprobó cuando escribió las credenciales (ver Figura 2). Lo que ocurre una vez que la aplicación tiene el token de acceso depende de las necesidades de la misma. El token se puede usar para recuperar, por ejemplo, la dirección de correo electrónico y almacenarla en un sistema de suscripción propio de la aplicación. El token también se puede usar para publicar en nombre del usuario. La cookie de autenticación de ASP.NET permanece válida, incluso cuando el usuario se desconecta de Twitter. Sin embargo, la aplicación no puede publicar si el usuario se desconecta de Twitter.

LA API de ASP.NET MVC, específicamente la clase OAuthWeb­Security, aborda satisfactoriamente la autenticación, pero abarca las interacciones con el proveedor social más allá de obtener un nombre para mostrar. También se integra bien con el proveedor de pertenencia simple de Web Pages para almacenar los nombres de usuario de Twitter y Facebook en forma local.

Dino Esposito es autor de “Architecting Mobile Solutions for the Enterprise” (Microsoft Press, 2012) y “Programming Microsoft ASP.NET MVC 3” (Microsoft Press, 2011), y coautor de “Microsoft .NET: Architecting Applications for the Enterprise” (Microsoft Press, 2008). Con residencia en Italia, Esposito participa habitualmente en conferencias y eventos del sector en todo el mundo. Puede seguir a Dino por Twitter en twitter.com/despos.

Gracias al siguiente experto técnico por su ayuda en la revisión de este artículo: Mani Subramanian (Microsoft)
Mani Subramanian ha estado involucrado en el desarrollo y la realización de pruebas de proyectos de software durante los últimos 12 años, con un enfoque en SOA, informática en nube y core.net.