Showing posts with label facebook. Show all posts
Showing posts with label facebook. Show all posts

Friday, November 5, 2010

Integración Facebook - ASP.NET con Graph API (III)

En esta última parte del post acerca de la integración de Facebook con ASP.NET (parte 1 y parte 2) explicaré por encima el nuevo método de autenticación que utilizaremos para poder postear comentarios en el muro ASP.NET de nuestro grupo de Facebook, OAuth.

Al parecer OAuth está últimamente arrasando en cuando a protocolos de autenticación se refiere, y ya lo están utilizando Google, Twitter, y Facebook, entre otros muchos.

Graph API utiliza OAuth 2.0 como método de autenticación basado en el intercambio de tokens. Como ya comentamos en la segunda parte de este post, lo primero que tenemos que hacer para recuperar cualquier tipo de dato de las entrañas de Facebook (posts, imágenes, información de usuarios) es obtener un access token público. Una vez obtenido ese token, podremos solicitar un access token privado, con el que el usuario podrá interactuar con Facebook. La recuperación de este token privado implica los siguientes pasos:
  • Obtención de un token público con el que poder instanciar un nuevo objeto de nuestro conector FacebookAPI (al que si os acordáis deberemos pasar el AppID y el AppSecret de nuestra aplicación residente en FB).
  • Solicitud de un access token privado, mediante redirección a la página de autenticación de Facebook (en donde el usuario introducirá su login y password) pasándole por parámetro el token público que ya tenemos.
  • Redirección por parte de Facebook, y sólo en caso de éxito en el login, a la página configurada en la Postback Url de la aplicación residente en FB, en donde se nos pasa por parámetro un código para intercambiar por el access token privado.
  • Obtención de un token privado al intercambiarlo por el código devuelto.
  • Una vez tenemos el nuevo access token privado, podemos desechar el público y utilizar éste, que nos permitirá realizar llamadas POST sobre el objeto FacebookAPI para postear datos, o simplemente poder obtener los comentarios de los posts en el muro.

Como véis, éste método tiene 2 claras ventajas:
  • Delega en Facebook la crítica parte de login/password que siempre nos puede traer de cabeza, y...
  • Nos proporciona un token con una vida de 60 minutos que tendremos que incluir en cada llamada a Facebook, y con el que tendremos acceso al mundo Facebook.

Genial, ¿no? Pues vamos con un poco de código.

En el botón estilo "Connect with Facebook" manejamos el evento del click generando una URL de autenticación del estilo https://graph.facebook.com/oauth/client_id=[]& redirect_uri=[]&scope=publish_stream,read_stream.



///
/// Handles the Click event of the btConnect control.
///

/// The source of the event.
/// The instance containing the event data.
protected void BtConnectClick(object sender, EventArgs e)
{
var api = new FacebookAPI(this.Token);
var authParameters = new Dictionary

{
{ "client_id", AppId },
{ "redirect_uri", PostbackUrl },
{ "scope", "publish_stream,read_stream" }
};
var urlConnect = api.GetAuthorizeUrl(authParameters);

this.Response.Redirect(urlConnect.AbsoluteUri, true);
}


Si el usuario autoriza realiza el login con éxito y autoriza la aplicación, Facebook redirige al usuario de vuelta con un código que utilizaremos para intercambiar por el token privado. Este intercambio lo realizaremos mediante llamando a nuestro método sobrecargado GetAccessToken, esta vez con más parámetros que en la parte 2 de este post.


///
/// Gets the access token for authenticated users.
///

/// The app id.
/// The app secret.
/// The redirect URL.
/// The app code from callback.
/// Authenticated access token.
public static string GetAccessToken(string appId, string appSecret, string redirectUrl, string appCodeFromCallback)
{
if (string.IsNullOrEmpty(appId) || string.IsNullOrEmpty(appSecret) || string.IsNullOrEmpty(redirectUrl) ||
string.IsNullOrEmpty(appCodeFromCallback))
{
return null;
}

var url =
string.Format(
"https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}&req_perms=publish_stream",
appId,
redirectUrl,
appSecret,
appCodeFromCallback);

string accessTokenValue = null;
var request = WebRequest.Create(url) as HttpWebRequest;

try
{
if (request != null)
{
using (var response
= request.GetResponse() as HttpWebResponse)
{
if (response != null)
{
var reader
= new StreamReader(response.GetResponseStream());

// access_token is the first of the parameters
accessTokenValue = reader.ReadToEnd();
accessTokenValue = accessTokenValue.Split(new[] { "&" }, StringSplitOptions.RemoveEmptyEntries)[0];
accessTokenValue = accessTokenValue.Replace("access_token=", string.Empty);
}
}
}
}
catch (WebException e)
{
throw new FacebookAPIException("Server Error", e.Message);
}

return accessTokenValue;
}


Con este access token privado podremos hacer llamadas como postear un nuevo mensaje en el muro de nuestro grupo de Facebook, a través de una llamada al método ya visto Call, pero de tipo POST.


///
/// Makes a Facebook Graph API POST request.
///

/// The path for the call,
/// e.g. /username
/// A dictionary of key/value pairs that
/// will get passed as query arguments. These determine
/// what will get set in the graph API.
/// JSON object of the request.
public JSONObject Post(string relativePath, Dictionary args)
{
return this.Call(relativePath, HttpVerb.POST, args);
}


Y podremos gestionar el evento click del botón de postear un nuevo comentario así:


///
/// Handles the Click event of the btMessage control.
///

/// The source of the event.
/// The instance containing the event data.
protected void BtMessageClick(object sender, EventArgs e)
{
var api = new FacebookAPI(this.Token);
var url = string.Format("/{0}/feed", GroupId);
var postParameters = new Dictionary

{
{ "message", this.tbMessage.Text }
};
api.Post(url, postParameters);
}


Colgaré todo el código de esta mini-integración con la GraphAPI en un futuro, pero de momento aquí finaliza esta serie de posts.

Espero que os haya resultado interesante. En la mente tengo hacer algo del estilo para Android, aunque todavía queda mucho para eso, ufff...

Por supuesto cualquier otra idea será muy bien recibida :-)


Wednesday, October 27, 2010

Integración Facebook - ASP.NET con Graph API (II)

Como comentaba en la primera parte de este post sobre la Graph API de Facebook, para poder recuperar cualquier tipo de dato es necesario obtener un AccessToken de Facebook. Recordemos que existen 2 tipos de token, uno público y otro privado.

Lo primero que haremos en este post una vez tengamos los datos de nuestra aplicación residente en nuestro perfil de Developer de Facebook (appId, appSecret, GroupId,...), será la llamada al siguiente método de la API para C# que hemos modificado convenientemenre y que será con la que trabajaremos.



///
/// Gets the access token for public access.
///

/// The app id.
/// The app secret.
/// Public access token.
public static string GetAccessToken(string appId, string appSecret)
{
if (string.IsNullOrEmpty(appId) string.IsNullOrEmpty(appSecret))
{
return null;
}

var url = string.Format(
"https://graph.facebook.com/oauth/access_token?type=client_cred&client_id={0}&client_secret={1}",
appId,
appSecret);

string accessTokenValue = null;
var request = WebRequest.Create(url) as HttpWebRequest;

try
{
if (request != null)
{
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback (CertificateValidationCallBack);

using (var response
= request.GetResponse() as HttpWebResponse)
{
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
accessTokenValue = reader.ReadToEnd().Replace("access_token=", string.Empty);
}
}
}
}
catch (WebException e)
{
throw new FacebookAPIException("Server Error", e.Message);
}

return accessTokenValue;
}


Como veis, este método static de la API lo que hace es únicamente crear un WebRequest a la dirección https://graph.facebook.com/oauth, y recuperar el parámetro access_token que devuelve dicha llamada. Ése será nuestro public AccessToken a partir de ahora, almacenado en PublicToken al hacer la siguiente llamada:


this.PublicToken = FacebookAPI.GetAccessToken(AppId, AppSecret);


Las consultas públicas las haremos a través de la Graph API, pasando este PublicToken siempre como parámetro. Así, en cada nueva consulta de, por ejemplo, el muro de un grupo de Facebook del cual tenemos su identificador (GroupId), instanciamos un nuevo objeto FacebookAPI y asignamos los datos recuperados a un objeto JSON.


///
/// Gets or sets the feed.
///

/// The wall's feed.
public JSONObject Feed
{
get
{
return this.feed;
}
set
{
this.feed = value;
}
}



// API call and get data from Facebook
var api = new FacebookAPI(this.Token);

// Format url
var url = string.Format("/{0}/feed", GroupId);

// Format args - get all data
var args = new Dictionary
{
{ "metadata", "1" }
};
this.Feed = api.Get(url, args);


Lo que la llamada a api.Get("/[GroupId]/feed") devuelve es el objeto JSON del que tendremos que hacer el DataBind con el control web que hemos incluído en nuestra aplicación. En mi caso es un Repeater.



///
/// Handles the ItemDataBound event of the rptDataWall control.
///

/// The source of the event.
/// The instance containing the event data.
protected void RptDataWallItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item e.Item.ItemType == ListItemType.AlternatingItem)
{
var apiItem = new FacebookAPI(this.Token);

// Get controls
var lbCreatedTime = (Label)e.Item.FindControl("lbCreatedTime");
var lbFrom = (Label)e.Item.FindControl("lbFrom");
var lbMessage = (Label)e.Item.FindControl("lbMessage");
var imgUserPic = (Image)e.Item.FindControl("imgUserPic");
var rptDataWallReply = (Repeater)e.Item.FindControl("rptDataWallReply");

// Databind
lbCreatedTime.Text = ((JSONObject)e.Item.DataItem).Dictionary["created_time"].DateTime.ToShortDateString() + " @ " + ((JSONObject)e.Item.DataItem).Dictionary["created_time"].DateTime.ToShortTimeString();
lbFrom.Text = ((JSONObject)e.Item.DataItem).Dictionary["from"].Dictionary["name"].String;
lbMessage.Text = ((JSONObject)e.Item.DataItem).Dictionary["message"].String;

// Get profile picture
var urlPictureProfile = string.Format("/{0}/picture", ((JSONObject)e.Item.DataItem).Dictionary["from"].Dictionary["id"].String);
imgUserPic.ImageUrl = apiItem.GetProfilePicture(
urlPictureProfile,
null).AbsoluteUri;

// Replies - FB restriction: only show when logged
if (((JSONObject)e.Item.DataItem).Dictionary.ContainsKey("comments"))
{
rptDataWallReply.ItemDataBound += new RepeaterItemEventHandler(this.RptDataWallReplyItemDataBound);
rptDataWallReply.DataSource = ((JSONObject)e.Item.DataItem).Dictionary["comments"].Dictionary["data"].Array;
rptDataWallReply.DataBind();
}
}
}


Así, estamos mostrando en el Repeater una cadena de posts de un wall de un grupo de Facebook. Algo del estilo como la siguiente imagen.




Y ya tenemos un muro más parecido al Notepad que al Facebook al que estamos habituados ;)

En la siguiente parte del post nos centraremos en obtener un token privado y en cómo sacarle rendimiento (obtener comentarios de comentarios, postear en el muro de un grupo, etc...).

Saturday, October 23, 2010

Integración Facebook - ASP.NET con Graph API (I)

Desde hace tiempo las redes sociales van tomando más importancia en nuestro día a día, ya sea en el trabajo o en nuestra vida privada. Tanto Facebook como Tuenti Twitter ofrecen unas estupendas APIs, abiertas a que programadores de todo el mundo incluyan componentes sociales en sus portales, en aplicaciones de escritorio o incluso en aplicaciones para móviles. En este post voy a hablar sobre cómo integrar un muro de un grupo de Facebook y cómo autenticarse y postear desde una página ASP.NET al mismo muro utilizando la nueva Graph API de Facebook.

Antes de nada, recomiendo pasarse por la documentación de la Graph API y por la de OAuth. Como veréis en los enlaces, absolutamente toda la interacción con Facebook (tanto gets como posts) se hace mediante llamadas del estilo https://graph.facebook.com/ID. Cualquier tipo de datos (perfiles de usuario, grupos, imágenes, posts del muro, etc), se obtiene en el objeto JSON que devuelve este tipo de llamadas HTTP. Probad por ejemplo mi perfil: https://graph.facebook.com/guisuraga -ese soy yo en FB! :)-. Otro enlace realmente interesante para entender lo que hacen este tipo de llamadas es el de este ingeniero de Google.

Es necesario que también os registréis con un perfil de Developer en Facebook. Desde esa página debéis añadir una nueva aplicación y configurarla. Guardad los datos del Application ID, Application Secret y API Key porque serán necesarios para hacer las llamadas desde vuestra aplicación. Esta aplicación en Facebook es la encargada de rutear las solicitudes a la Graph API de Facebook, y devolver los datos solicitados por vuestra aplicación.


Ahora que tenemos una idea del potencial de esta API y teniendo en cuenta nuestro objetivo de incluir este componente en una aplicación ASP.NET, lo más rápido (y fácil) es encontrar una buena API en .NET que nos ayude a recuperar los datos y a transformar ese objeto JSON en algo que podamos manejar más fácilmente. Creedme, he probado varias APIs, y ninguna es tan simple y funciona tan bien (con alguna pequeña modificación :P) como la que los propios chicos de Facebook sacaron hace poco para C#. La podéis descargar desde aquí.

Una vez compilada y añadida a nuestro proyecto, la referencia Facebook actúa de intermediario entre nuestra aplicación y Facebook. En cada nueva instancia de un objeto FacebookAPI es necesario pasar por parámetro un AccessToken proporcionado por Facebook al hacer una llamada a la URL https://graph.facebook.com/oauth/authorize. Existen dos tipos de tokens: uno para recuperar datos públicos (datos del muro, datos públicos de perfiles), y otro para recuperar datos de una sesión autenticada (comentarios de posts en el muro, información adicional de perfiles). Para el primero de ellos, es suficiente con proporcionar los datos de nuestra aplicación residente en Facebook. El AccessToken para la parte privada lo intentaré explicar más adelante (cuando nos metamos con OAuth).

En la próxima parte del post me meteré con el código que hace esto.