Autenticación en facebook desde un App Universal | C#

Intermedio

Aprenderemos a autenticarnos en facebook y consumir su API por medio de un App Universal, es decir un App para Windows Phone 8.1 y Windows 8.1.

En artículos anteriores hemos explorado los fundamentos necesarios para que este artículo sea provechoso. Les recomiendo leer estos artículos antes de leer este para que todo el contenido expuesto pueda ser captado fácilmente.

Artículos relacionados

Windows Phone - Métodos AndContinue

Windows Phone, WebAuthenticationBroker y métodos AndContinue | C#

Para autenticarse en facebook es necesario hacer uso de su API REST, y desde luego como siempre el primer paso es autenticarnos en facebook para lograr obtener un token, de allí en más es solo utilizar los endpoint de facebook para cada operación que se valla a realizar.

No reinventar la rueda y Facebook SDK for Windows

Hay muchas cosas respecto a facebook SDK que pueden ser muy engorrosas, sin embargo no debemos preocuparnos demasiado por ello, hoy en día existe una amplia gama de componentes para Windows / Windows Phone que se han encargado de resolver varios temas, especialmente haré referencia a Facebook SDK for Windows un SDK desarrollado y mantenido por Microsoft.

Dónde está el SDK para Windows Phone?

Facebook SDK tambien soporta Windows Phone con una API enfocada a dicho sistema, pero ya que estamos trabajando con Apps universales debemos usar la misma API para Facebook SDK de Windows.

Preparación

Para efectos de la app que crearemos en este artículo creamos una solución de App Universal con proyecto de tipo Hub:

Proyecto tipo Hub

Una vez creada procedemos a borrar las páginas xaml que vienen con el template ya que no las necesitamos.

Instalación de Facebook SDK

Para instalarlo lo haremos por el administrador de paquetes "Nuget" a mi particularmente me gusta usar la consola ;)

Abriendo NuGet

 PM> Install-Package Facebook  

Esto agregará Facebook SDK en el proyecto actual, así que es necesario utilizar la lista desplegable (en rojo) para alternar entre proyectos e instalar la referencia indicada en cada uno.

Instalación de Facebook SDK por NuGet

Configuración de la App en Facebook

Si tu app se va a conectar con Facebook, Mark Zuckerberg debe saberlo.

Hay que ir al portal para desarrolladores de facebook y allí registrar tu nueva App.

Crear nueva app de facebook

En el panel la diligenciamos como consideremos pertinente, el segundo parámetro es opcional.

El nombre no puede tener nada relacionado con facebook porque no te lo aprobarán y el Guid debe ser max. de 20 caracteres y en minúscula.

Crear app en facebook

A Continuación se abre un panel, vamos a la sección Settings allí damos click en adicionar plataforma:

Settings en la configuración de facebook

Hecho esto se debe seleccionar Windosw como plataforma.

Adicionar Windows como plataforma en un App de Facebook

Como estamos creando un App universal ignoraremos el campo que habla de Windows Phone y nos fijaremos únicamente en el de Windows Store ID.

Hay un par de formas de obtener el valor que se debe poner en ese campo, una de ellas la pueden ver en el artículo "Windows Phone, WebAuthenticationBroker y métodos AndContinue | C#" la otra es la que explicaré en este artículo y para efectos de una app en producción es la forma más conveniente.

Configuración de la App de Windows Store

Desde Visual Studio procedemos reservar el nombre de la App en Windows Store.

Sino tienes cuenta de publicación puedes hacer uso de la técnica mostrada en el artículo arriba citado.

Reservar Nombre de App desde Visual Studio

Reservar Nombre de App desde Visual Studio

Una vez este reservado el nombre vamos al panel de nuestra cuenta de Windows Store y procedemos a modificar la App.

Modificar Windows Store App

Vamos directamente a la configuración de servicios

Configuración de servicios

y Allí encontramos el link para configurar los servicios de Live:

Acceso al sitio de servicios de Live

Apenas abre la página encontramos el sId de la App, este valor lo debemo poner de vuelta en el Windows Store Id preguntado por facebook.

Windows Store App sid

Para usarlo en facebook se debe omitir el protocolo y los slash.

Facebook Windows Store Id

Configurando la App de Windows Phone

Ya estando completo el proceso de la App de Windows Store el proceso de la App de Windows Phone es más sencillo, lo único que hay que hacer es asociar la app de Windows Phone con el nombre reservado anteriormente para Windows Store.

Reservar Nombre de App desde Visual Studio

Reservar Nombre de App desde Visual Studio

Interfaz para login

Creamos en la App de Windows Store una página básica llamada FBBasicPage con los controles mostrados a continuación, recuerden que pueden obtener la imagen de facebook mostrada en el artículo anterior:

 <!--TODO: Content should be placed within the following grid-->  
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,9.5,19,0">  
    <StackPanel Margin="0,0,963,0">
        <Button x:Name="btnFacebookLogIn"
        Margin="50,10,50,10" 
        HorizontalAlignment="Stretch"
        Click="btnFabookLogin_Click">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*"/>
                    <ColumnDefinition Width="2*"/>
                </Grid.ColumnDefinitions>

                <Image Source="ms-appx:///Assets/Images/Facebook.png"
                Stretch="Uniform"
                Margin="10"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"/>
                <TextBlock Margin="10" Grid.Column="1" 
            VerticalAlignment="Center"
            Text="Facebook Login"/>
            </Grid>
        </Button>
        <TextBox x:Name="txtFbToken" 
            Margin="50,0,50,0" 
            PlaceholderText="facebook token" 
            IsReadOnly="True" 
            Height="340" 
            TextWrapping="Wrap"/>
    </StackPanel>
</Grid>  

Quedando la interfaz así:

Windows Store App UI

Hacemos la misma operación en Windows Phone, creamos la página FBBasicPage y adicionamos los mismos controles, elimina el atributo Margin del StackPanel. Quedando así:

Windows Phone App UI

Facebook manager

Ahora comenzamos a trabajar con el código de la app.

Creamos una carpeta llamada Manager, pero la debemos crear en los tres proyectos:

  • Windows 8.1
  • Windows Phone 8.1
  • Shared

Vamos al proyecto Shared y allí creamos una nueva clase llamada FacebookManager esta clase debemos definirla como partial. Les recomiendo que el archivo lo nombren FacebookManager.Shared.cs.

En ella declaramos las siguientes propiedades:

 partial class FacebookManager  
{
    readonly FacebookClient _fb = new FacebookClient();
    readonly Uri _callbackUri = WebAuthenticationBroker.GetCurrentApplicationCallbackUri();
    readonly Uri _loginUrl;

    public string AccessToken
    {
        get { return _fb.AccessToken; }
    }
}

FacebookClient es una clase que esta definida en el Facebook SDK y tiene varios utilitarios que nos facilitarán la vida, uno de ellos sirve para crear la URL de login en facebook, que no es tan dificil de crear, pero como suele pasar, somos humanos y cometemos errores que luego no los podemos solucioanr facilmente.

_callbackUri es la Uri a la cual nos devolvera la app una vez el proceso de autenticación haya concluido, a esta le hemos asignado un Uri especial que hará que desde facebook se retorne a nuestra App. Este valor corresponde también al sid que hemos matriculado en el portal de facebook para la app.

Así que ahora en el constructor de la clase inicializaremos _loginUrl utilizando _fb.

 public FacebookManager()  
{
    _loginUrl = _fb.GetLoginUrl(new
            {
                client_id = App.Current.Resources["FacebookAppId"],
                redirect_uri = _callbackUri.AbsoluteUri,
                scope = App.Current.Resources["FacebookPermissions"],
                display = "popup",
                response_type = "token"
            });
}

En la inicialización hacemos uso de dos recursos:

  • FacebookAppId
  • FacebookPermissions

Intencionalmente los he colocado como recursos de la aplicación, para tenerlos así solo hace falta crear los recursos en el xaml de la clase App.

 <Application  
    x:Class="FacebookSDKSample.App"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:FacebookSDKSample">

    <Application.Resources>
        <x:String x:Key="FacebookAppId">1x683yyyyy4371ppp5</x:String>
        <x:String x:Key="FacebookPermissions">public_profile</x:String>
    </Application.Resources>
</Application>  

FacebookAppId lo obtenemos del panel de configuración de nuestra app en facebook. En FacebookPermissions tenemos asignado public_profile que son los permisos mínimos requeridos, de hecho es el permiso por defecto. Es recomendable siempre pedir tan pocos permisos como sea posible, porque facebook todo el tiempo esta volviendose más restrictivo y si pides permisos que no necesitas un dia tu app dejará de funcionar por que ya ese permiso no es permitido.

En resumen el parámetro que pasamos al método GetLoginUrl es un objeto, en este caso anónimo, con los campos requeridos para formar la url de login para facebook, este método se encarga de contatenar todo lo necesario así como de hacer el URL encoding.

Capturar la respuesta después del login

El login es diferente dependiendo si estamos en Windows Phone o en Windows Store apps, esto por el tema de manejo de memoria, así que veremos primero como reaccionar ante la respuesta del login lo cual se hace identico en cualquier caso.

Esto no tiene mayor complicación, este es mi código para manipular la respuesta.

 private void ValidateAndProccessResult(WebAuthenticationResult result)  
{
    if (result.ResponseStatus == WebAuthenticationStatus.Success)
    {
        var responseUri = new Uri(result.ResponseData.ToString());
        var facebookOAuthResult = _fb.ParseOAuthCallbackUrl(responseUri);

        if (string.IsNullOrWhiteSpace(facebookOAuthResult.Error))
            _fb.AccessToken = facebookOAuthResult.AccessToken;
        else
        {//error de acceso denegado por cancelación en página
        }
    }
    else if (result.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
    {// error de http
    }
    else
    {// otras condiciones de error
    }
}

El método recibe WebAuthenticationResult el cual es devuelto por el WebAuthenticationBroker una vez se ha finalizado el login.

Que la respues del WebAuthenticationBroker sea exitosa no implica que el Login haya sido exitoso, por lo que hay que revisar la respuesta entregada por Facebook, la cual es una Uri con parámetros, en dichos parámetros es donde realmente nos dice si fue o no exitoso.

Si bien podemos revisar los parámetros manualmente, es mejor hacer uso del método ParseOAuthCallbackUrlel cual nos devuelve un FacebookOAuthResult con todos los campos ya por separado.

Cuando la respuesta es exitosa asignamos el AccessToken en el FacebookClient.

Si eres fiel seguidor del blog ya sabrás que el tema en Windows Phone es un poco más complicado dada la necesidad de usar métodos AndContinue, así que arrancaremos de primeras con Windows Store.

Login en Windows Store App

En la carpeta manager del proyecto de Windows Store creamos nuevamente una clase FacebookManager y la definimos como partial. Les recomiendo que el archivo lo nombren FacebookManager.WindowsStore.cs.

Definimos un método asíncrono llamado LoginAsync desde el cual llamamos al WebAuthenticationBroker para autenticarnos.

 public async Task LoginAsync()  
{
    var result = await WebAuthenticationBroker.AuthenticateAsync(
                                                WebAuthenticationOptions.None,
                                                _loginUrl);

    ValidateAndProccessResult(result);
}

Una vez se ha llamado al WebAuthenticationBroker llamamos a nuestro método de validación, el cual hemos creado ya en nuestro proyecto Shared.

Login en Windows Phone App

En la carpeta manager del proyecto de Windows Store creamos nuevamente una clase FacebookManager y la definimos como partial. Les recomiendo que el archivo lo nombren FacebookManager.WindowsPhone.cs.

En Windows Phone debemos fraccionar el trabajo partes, primero el proceso de Login el cual va a poner nuestra App en estado de suspensión, y luego cuando la app es reactivada debemos finalizar el proceso haciendo las validaciones necesarias. Es muy similar al de Windows Store pero la lógica esta repartida en dos métodos y como se darán cuenta en este caso no se hace uso de instrucciones asíncronas, en su lugar se implementa el patrón AndContinue.

 public void LoginAndContinue()  
{
    WebAuthenticationBroker.AuthenticateAndContinue(_loginUrl);
}

public void ContinueAuthentication( WebAuthenticationBrokerContinuationEventArgs args )  
{
    ValidateAndProccessResult(args.WebAuthenticationResult);
}

Establecer el llamado de continuación

Una vez la App se activa nuevamente, y se inicia en la página que estaba activa antes de suspenderse, hay que llamar al método ContinueAuthentication de la clase FacebookManager. Sin embargo para que el Page pueda disparar dicho llamado debemos hacer algo desde su invocación.

Pensando en ellos procedemos a crear una carpeta Misc dentro del proyecto de Windows Phone y en ella creamos una interfaz como se ve a continuación:

 interface IWebAuthenticationBrokerContinuable  
{
    void ContinueWithWebAuthenticationBroker(WebAuthenticationBrokerContinuationEventArgs args);
}

Esta interfaz y método nos permitirá reconocer si el page activado tras la suspensión debe continuar con la labor de autenticación.

Editamos la clase FBBasicPage del proyecto, creamos una nueva instancia de FacebookManager, implementamos la interfaz y la hacemos implementar el método:

 public sealed partial class FBBasicPage : Page, IWebAuthenticationBrokerContinuable  
{
    //...
    FacebookManager _fbm = new FacebookManager();
    public void ContinueWithWebAuthenticationBroker(WebAuthenticationBrokerContinuationEventArgs args)
    {
        _fbm.ContinueAuthentication(args);
        txtFbToken.Text = _fbm.AccessToken;
    }
    //...
}

En el método implementado llamamos a ContinueAuthentication del FacebookManager y de paso asignamos el token obtenido en el textbox.

Warning Recuerden que el código esta expuesto de manera sencilla para que puedan aprender, sin embargo en condiciones ideales deberian utilizar MVVM y técnicas relacionadas para organizar su código.

Creando ContinuationManager

Ahora hay que modificar el proceso de activación de la App para que pueda invocar la página que estab abierta y de paso verificar si puede invocar al método ContinueWithWebAuthenticationBroker.

Para ello se creará una clase ContinuationManager en la carpeta Manager del proyecto de Windows Phone, con la lógica que se ve a continuación.

 class ContinuationManager  
{
    public void ContinueWith(IActivatedEventArgs args)
    {
        var rootFrame = Window.Current.Content as Frame;
        if (rootFrame == null)
            return;

        switch (args.Kind)
        {
            case ActivationKind.PickFileContinuation:
                break;
            case ActivationKind.PickFolderContinuation:
                break;
            case ActivationKind.PickSaveFileContinuation:
                break;
            case ActivationKind.WebAuthenticationBrokerContinuation:
                var continuator = rootFrame.Content as IWebAuthenticationBrokerContinuable;
                if (continuator != null)
                    continuator.ContinueWithWebAuthenticationBroker((WebAuthenticationBrokerContinuationEventArgs)args);
                break;
            default:
                break;
        }
    }
}

La explicación de este método la puedes ver en el artículo anterior:

Windows Phone, WebAuthenticationBroker y métodos AndContinue | C# (link directo a la sección)

Para que la App se incie en la página que estaba activa antes de suspenderse se debe modificar el manejador del evento OnActivated de la clase App - archivo App.xaml.cs

Pero esta funcionalidad solo la necesitamos en efecto solo la podemos crear para Windwos Phone, por lo que debemos hacer lo siguiente:

  1. En el proyecto Shared editamos App.xaml.cs y marcamos la clase como partial
  2. Ahora en el proyecto de Windows Phone, en el root folder, creamos una clase llamada App y la marcamos como partial. Esto es la misma clase partial del proyecto Shared pero acá colocaremos solo el código que es válido para Windows Phone, les recomiendo nombrar el archivo App.WindowsPhone.cs .
 public sealed partial class App : Application  
{
    ContinuationManager _continuator = new ContinuationManager();

    protected async override void OnActivated(IActivatedEventArgs args)
    {
        CreateRootFrame();

        if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
        {
            try
            {
                await SuspensionManager.RestoreAsync();
            }
            catch { }
        }

        if (args is IContinuationActivatedEventArgs)
            _continuator.ContinueWith(args);

        Window.Current.Activate();
    }

    private void CreateRootFrame()
    {
        Frame rootFrame = Window.Current.Content as Frame;
        if (rootFrame == null)
        {
            rootFrame = new Frame();
            SuspensionManager.RegisterFrame(rootFrame, "AppFrame");
            Window.Current.Content = rootFrame;
        }
    }
}

Se ha creado una instancia del ContinuationManager y en el proceso de activación de la App se valida la ventana actual, se restaura la sesión anterior con ayuda del SuspensionManager(el cual viene en el template que escogimos para crear el proyecto) y finalmente se llama al método ContinueWith del ContinuationManager el cual tiene la lógica para determinar que tipo de continuación se debe realizar.

Nuevamente sugiero ver el artículo anterior si quieren entrar en más detalles.

Por claridad del proceso que acabo de realizar les dejo acá un diagrama que hace parte de uno de los artículo anteriores.

Windows Phone - Métodos AndContinue

AndContinue Method life cycle

Enlazando la UI con el Login

Ahora que tenemos la UI y el proceso de Login listo, procedemos a enlazarlo ambos. En la clase FBBasicPage hacemos lo siguiente.

  1. Crear el manejador del evento Click del botón
  2. Crear un campo FacebookManager (en windows phone ya lo tenemos creado)
  3. En el manejador del evento llamar al método del FacebookManager correspondiente en ada caso

En el caso de Windows Store App el manejador del evento queda así:

 private async void btnFabookLogin_Click(object sender, RoutedEventArgs e)  
{
    await _fbm.LoginAsync();
    txtFbToken.Text = _fbm.AccessToken;
}

Y para Windows Phone App

 private void btnFabookLogin_Click(object sender, RoutedEventArgs e)  
{
    _fbm.LoginAndContinue();
}

Ejecución

Al ejecutar la App de Windows Store tenemos:

Facebook login desde WinRT App

Facebook Auth desde WinRT App

Token de facebook obtenido desde app WiRT

Y en la App de Windows Phone:

Facebook login desde Windows Phone App

Facebook Auth desde Windows Phone App

Token de facebook obtenido desde app Windows Phone

Y eso es todo!!

Ahora que tenemos el token autenticado pueden valerse de Facebook SDK para poder hacer consultas en la plataforma.

Hasta pronto.

Código fuente de este artículo

JuanKRuiz GitHub

Este es todo el código creado y/o modificado para que lo puedan reutilizar. Esta colgado en Gists de Githbub.

Código relacionado con el post "Autenticación manual en facebook desde un App Universal | C#"