Nota: Este post ha sido importado de mi blog de geeks.ms. Es posible que algo no se vea del todo "correctamente". En cualquier caso puedes acceder a la versión original aquí
Buenas! El objetivo de este post es explicar la solución a la que he llegado para integrar autenticación con oAuth en un sitio web desarrollado con NancyFx. En este primer post veremos como hacerlo “de la forma clásica” pero en otro siguiente nos aprovecharemos de los componentes de autenticación de Katana.
Iré hablando en este blog más sobre OWIN, Katana y también sobre NancyFx, pero por el momento algunas definiciones rápidas:
- OWIN: Especificación que indica como deben comunicarse los servidores web, el middleware web y las aplicaciones web en .NET.
- Katana: Implementación de varios componentes (hosts, servidores, middlewares varios) OWIN por parte de Microsoft.
- NancyFx: Un framework basado en el patrón MVC para desarrollar aplicaciones web y APIs REST. Por decirlo de algún modo NancyFx “compite” con ASP.NET MVC y con WebApi a la vez.
Para saber más de OWIN hay un par de posts en mi blog pero también una serie fenomenal del Maestro. Échales un ojo.
Creando una aplicación Nancy ejecutándose en IIS
Vamos a crear una aplicación web, y vamos a usar NancyFx en lugar de ASP.NET, pero usando IIS (IISExpress).
NancyFx viene en dos “sabores”: puede ser un HttpHandler de ASP.NET (así instalas y configuras NancyFx usando el web.config), pero también existe como componente OWIN, lo que permite su uso dentro de cualquier entorno OWIN.
Para usar NancyFx como HttpHandler de ASP.NET debes instalar el paquete Nancy.Hosting.Aspnet que es el que contiene todas las referencias a ASP.NET (NancyFx es totalmente independiente de ASP.NET). Ahora vamos a crear una aplicación web ASP.NET, así que lo lógico parece ser usar NancyFx como HttpHandler y listos. En muchos casos puede ser lo más lógico, pero no es lo que vamos a hacer. No vamos a usar NancyFx como HttpHandler de ASP.NET. En su lugar lo vamos a utilizar como componente OWIN y, para ello, nos aprovecharemos de un componente de Katana que permite usar componentes OWIN dentro del pipeline de ASP.NET (en terminología OWIN diríamos que este componente de Katana implementa un Host y un servidor Web OWIN). Esto parece dar muchas vueltas, y en muchos casos así puede ser, pero tiene las siguientes ventajas:
- Dado que nuestra aplicación será OWIN en cualquier momento podremos abandonar el cómodo regazo de IIS e irnos a cualquier otro host o servidor OWIN.
- Incluso aunque no tengamos pensado divorciarnos de IIS, podremos utilizar cualquier componente OWIN que haya por ahí 😉
Como digo, para poder utilizar NancyFx como componente OWIN pero ejecutándose en un pipeline de ASP.NET necesitamos la ayuda de Katana, en concreto del componente Microsoft.Owin.Host.SystemWeb.
Así, los pasos para usar NancyFx como componente OWIN dentro del pipeline de ASP.NET son los siguientes. Antes que nada crea un proyecto de tipo ASP.NET y selecciona el template “Empty”:
Luego instala los siguientes paquetes de NuGet:
- Nancy (el core de NancyFx)
- Nancy.Owin (Para usar Nancy como módulo OWIN)
- Microsoft.Owin.Host.SystemWeb (Para usar módulos OWIN en el pipeline de ASP.NET)
Con esto ya tenemos el esqueleto necesario.
El siguiente paso es crear la clase de inicialización de OWIN. Para ello agrega una clase normal y llámala Startup:
<div style="background: #ddd; max-height: 300px; overflow: auto">
<ol start="1" style="background: #1e1e1e; margin: 0 0 0 2em; padding: 0 0 0 5px; white-space: nowrap">
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">public</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">class</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#4ec9b0">Startup</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> {</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">public</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">void</span><span style="background:#1e1e1e;color:#dcdcdc"> Configuration(</span><span style="background:#1e1e1e;color:#b8d7a3">IAppBuilder</span><span style="background:#1e1e1e;color:#dcdcdc"> app)</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> {</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> app</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">UseNancy();</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> }</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> }</span>
</li>
</ol>
</div></p>
Es importante que la clase se llame Startup. Esto es una convención que sigue Katana (pues quien inicializa los módulos OWIN es Katana a través del paquete Microsoft.Owin.Host.SystemWeb). Si nuestra clase tiene otro nombre recibirás un error como el siguiente:
Una solución es o bien renombrar la clase para que se llame Startup o en el caso de que no quieras hacerlo usar el atributo OwinStartupAttribute:
- [assembly: OwinStartup(typeof(MyCustomStartup))]
Si ahora ejecutas la aplicación deberías ver algo parecido a lo siguiente:
Eso significa que Nancy está funcionando correctamente (este 404 ha sido servido por Nancy). ¡Felicidades! Ya tienes a Nancy corriendo bajo IIS.
Vamos ahora a crear un módulo de Nancy (más o menos equivalente a un controlador de ASP.NET MVC), para gestionar la llamada a la URL / y mostrar una vista con solo el enlace “Login with twitter”. Añade una clase a tu proyecto con el siguiente código:
<div style="background: #ddd; max-height: 300px; overflow: auto">
<ol start="1" style="background: #1e1e1e; margin: 0 0 0 2em; padding: 0 0 0 5px; white-space: nowrap">
<li>
<span style="background:#1e1e1e;color:#569cd6">public</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">class</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#4ec9b0">MainModule</span><span style="background:#1e1e1e;color:#dcdcdc"> : </span><span style="background:#1e1e1e;color:#4ec9b0">NancyModule</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc">{</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">public</span><span style="background:#1e1e1e;color:#dcdcdc"> MainModule()</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> {</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> Get[</span><span style="background:#1e1e1e;color:#d69d85">"/"</span><span style="background:#1e1e1e;color:#dcdcdc">] </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> _ </span><span style="background:#1e1e1e;color:#b4b4b4">=></span><span style="background:#1e1e1e;color:#dcdcdc"> View[</span><span style="background:#1e1e1e;color:#d69d85">"main.html"</span><span style="background:#1e1e1e;color:#dcdcdc">];</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc"> }</span>
</li>
<li>
<span style="background:#1e1e1e;color:#dcdcdc">}</span>
</li>
</ol>
</div></p>
Con esto has creado un módulo de NancyFx y has enrutado todas las peticiones que vayan a la URL “/” para que muestren la vista main.html. Añade pues un archivo main.html (no es necesario que esté en ninguna carpeta Views ni nada) que muestre un enlace a la URL “/authentication/redirect/twitter”.
Si ahora ejecutas el proyecto deberías se tendría que ver el contenido del fichero main.html. Y si pulsas sobre el enlace tienes que recibir el 404 de Nancy.
Perfecto! Ya tenemos el esqueleto base de la aplicación. Ahora vayamos a integrar la autenticación por twitter.
Integrando oAuth con NancyFx a la manera clásica
Nota: El contenido de este apartado presupone que tienes creada una aplicación en twitter y que por lo tanto tienes un consumer key y un consumer secret. También debes configurar la aplicación twitter para que la URL de callback sea /authentication/authenticatecallback">http://localhost:
/authentication/authenticatecallback Nota 2: Twitter (y otros proveedores oAuth) no dejan dar de alta aplicaciones cuyo callback sea una dirección de localhost. En este caso lo más rápido es usar el dominio xxx.localtest.me (usa cualquier valor para xxx). El dominio localtest.me está especialmente pensado para estos casos: cualquier subdominio en localtest.me resuelve a 127.0.0.1 😉
NancyFx es un framework muy modular, y no tiene incorporado el concepto de autenticación o autorización. Eso significa que no hay por defecto ninguna API ni nada que nos diga si el usuario está autenticado o bien poder autenticarlo. Todo eso se deja a implementaciones “externas” al core de NancyFx.
P. ej. si queremos autenticar nuestra aplicación basándonos en cookies (lo que en el mundo ASP.NET conocemos como autenticación por forms) debemos instalar el paquete Nancy.Authentication.Forms. Hay otros paquetes para otros tipos de autenticación (como puede ser Nancy.Authentication.Basic para autenticación básica de HTTP o bien Nancy.Authentication.Stateless para basar la autenticación en alguna cabecera específica de la petición). Todos estos paquetes (y más que hay para otros tipos de autenticación) se basan en el modelo de extensibilidad de NancyFx.
Por supuesto hay un paquete para integrarnos con oAuth que antes respondía al interesante nombre de Nancy.Authentication.WorldDomination pero que ahora tiene el aburrido y anodino nombre de Nancy.SimpleAuthentication. Así que añade este paquete a tu proyecto y ya estarás listo para iniciar un flujo para autenticación.
Al añadir este paquete tu web.config se habrá modificado y se habrán añadido las siguientes líneas:
<div style="background: #ddd; max-height: 300px; overflow: auto">
<ol start="1" style="background: #1e1e1e; margin: 0 0 0 2.5em; padding: 0 0 0 5px; white-space: nowrap">
<li>
<span style="background:#1e1e1e;color:#808080"> <</span><span style="background:#1e1e1e;color:#569cd6">configSections</span><span style="background:#1e1e1e;color:#808080">></span>
</li>
<li>
<span style="background:#1e1e1e;color:#808080"> <</span><span style="background:#1e1e1e;color:#569cd6">section</span><span style="background:#1e1e1e;color:#808080"> </span><span style="background:#1e1e1e;color:#92caf4">name</span><span style="background:#1e1e1e;color:#808080">="</span><span style="background:#1e1e1e;color:#c8c8c8">authenticationProviders</span><span style="background:#1e1e1e;color:#808080">" </span><span s
tyle=“background:#1e1e1e;color:#92caf4”>type="SimpleAuthentication.Core.Config.ProviderConfiguration, SimpleAuthentication.Core" />
</configSections>
«/span>authenticationProviders>
«/span>providers>
«/span>add name="Facebook" key="please-enter-your-real-value" secret="please-enter-your-real-value" />
«/span>add name="Google" key="please-enter-your-real-value" secret="please-enter-your-real-value" />
«/span>add name="Twitter" key="please-enter-your-real-value" secret="please-enter-your-real-value" />
«/span>add name="WindowsLive" key="please-enter-your-real-value" secret="please-enter-your-real-value" />
</providers>
</authenticationProviders>