Autenticación manual 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 facilmente.
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 ´dia existe una amplia gama de compoentes 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:
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 ;)
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.
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.
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.
A Continuación se abre un panel, vamos a la sección Settings allí damos click en adicionar plataforma:
Hecho esto se debe seleccionar Windosw como plataforma.
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.
Una vez este reservado el nombre vamos al panel de nuestra cuenta de Windows Store y procedemos a modificar la App.
Vamos directamente a la configuración de servicios
y Allí encontramos el link para confoigurar los 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.
Para usarlo en facebook se debe omitir el protocolo y los slash.
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.
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í:
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í:
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 ParseOAuthCallbackUrl
el 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:
- En el proyecto Shared editamos App.xaml.cs y marcamos la clase como
partial
- Ahora en el proyecto de Windows Phone, en el root folder, creamos una clase llamada
App
y la marcamos comopartial
. 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
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.
- Crear el manejador del evento Click del botón
- Crear un campo
FacebookManager
(en windows phone ya lo tenemos creado) - 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:
Y en la App de 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.