Desarrollando un plugin WordPress para requerir login en Facebook

Introducción.

Este post explica cómo desarrollar un plugin que exija a los visitantes de nuestro blog WordPress loguearse en Facebook para poder ver ciertos contenidos.

Además de desarrollar el plugin, es necesario registrar una aplicación en Facebook para lograr esta funcionalidad.

Paso Previo: Registrar una aplicación Facebook.

Para que nuestro sitio entero o un post en particular utilice Facebook como sistema de autenticación, lo primero que deberemos hacer es registrar una aplicación en Facebook.

Esto puede sonar complejo, pero es más sencillo de lo que se cree. Se trata tan sólo de llenar un formulario en el sitio para desarrolladores de Facebook (developers.facebook.com). Este tema excede el alcance de este artículo, por lo que no se detallarán los pasos para hacerlo. Pero les dejo esta captura de pantalla del formulario para que se den una idea:

fblogin

Una vez que tengamos la aplicación nueva registrada, tendremos un “application/client id” y “application/client secret” asignados. Estos dos datos son lo que utilizaremos en nuestro plugin.

Ahora es donde comienza la parte interesante. Ya podemos dedicarnos al plugin para que el sitio o el post se autentique con Facebook.

Entendiendo el circuito de autenticación de OAUTH.

Facebook utiliza el estándar OAUTH como protocolo de autenticación para aplicaciones externas. Esto basicamente es que

  1. intentamos acceder al post; en este momento el plugin verifica que no estamos autenticados;
  2. nos redirecciona a la URI de login de facebook pasando como parámetro GET la URI del post (“redirect_uri”);
  3. ingresamos nuestro usuario y contraseña, entonces Facebook nos redirecciona de vuelta hacia la URI del post (“redirect_uri”), agregándole un nuevo parámetro llamado “code”;

    Sin entrar en detalles, “code” es un “id” único que crea Facebook cada vez que un usuario se loguea con su nombre y contraseña.

  4. nuestro plugin, utilizando este parámetro “code”, más otros parámetros que ya conocía previamente (“application/client id” y “application/client secret”), podrá comenzar a invocar los webservices de Facebook para establecer sesión, consultar datos del usuario (nombre, apellido, mail), postear, etc.

Consideraciones de Seguridad

La seguridad con OAUTH está garantizada debido a que jamás estamos ingresando nuestro nombre de usuario y contraseña en la aplicación externa (en la que podríamos no tener plena confianza), lo hacemos unicamente en Facebook y a través del protocolo HTTPS que es encriptado.

Por otro lado, la aplicación externa no puede ser sustituida (hackeando el DNS por ejemplo) tan fácilmente, debido a que la falsa aplicación debería disponer del código secreto (“application/client secret”).

El Plugin.

El plugin en sí mismo consta de un “content filter” y un “init action”.

El content filter

El content filter actuará sólo en los posts que posean el custom field “requirefacebooklogin”. Se encargará de filtrar el contenido del post y mostrarlo si y sólo si el usuario se encuentra autenticado. Caso contrario reemplazará el contenido del post por un botón que invite al usuario a loguearse en facebook.

Un usuario se considera autenticado si el atributo “facebookuser” se encuentra en la sesión. Este atributo es colocado en sesión por el “init action” que se detalla luego.

add_filter('the_content', 'fbplugin_content_filter');
function fbplugin_content_filter($content) {

	global $post;

	$requirefacebooklogin = get_post_custom_values('requirefacebooklogin');

	if (isset($requirefacebooklogin) && empty($_SESSION['facebookuser'])) {
		$app_id = "523032849926431";
		$app_secret = "dc67e6sdfadf407a82ddadf1b103f134439a13";
		$my_url = "http://titohernandez.com" . $_SERVER["REQUEST_URI"];

		$login_url = "https://www.facebook.com/dialog/oauth?client_id="
				. $app_id . "&redirect_uri=" . urlencode($my_url)
				. "&scope=email,user_location";

		$html = '<div>'
				. '<a href="' . $login_url . '">'
				. 'Facebook Login'
				. '</a>'
				. '</div>';

		return $html;
	}

	return $content;

}

El init action

El init action se encargará de verificar si la request incluye el parámetro “code”, lo que significaría que el usuario se acaba de loguear en facebook. En ese caso se deberá proceder en consecuencia. Aquí lo que hacemos es guardar en sesión los datos del usuario, particularmente en el atributo “facebookuser” y además enviarnos un mail con ellos.

add_action('init', 'fbplugin_init_action', 1);
function fbplugin_init_action() {

	if(!session_id()) {
		session_start();
	}

	if (isset($_REQUEST['code'])) {
		$app_id = "523032849926431";
		$app_secret = "dc67e6sdfadf407a82ddadf1b103f134439a13";
		$redirect_uri = preg_replace('/(\\?|&)?code=[^&]*/', '', "http://titohernandez.com" . $_SERVER["REQUEST_URI"]);

		$token_url = "https://graph.facebook.com/oauth/access_token?"
				. "client_id=" . $app_id . "&redirect_uri=" . urlencode($redirect_uri)
				. "&client_secret=" . $app_secret . "&code=" . $_REQUEST['code'];

		$response = file_get_contents($token_url);
		$params = null;

		parse_str($response, $params);

		$graph_url = "https://graph.facebook.com/me?access_token="
				. $params['access_token'];

		$user = null;
		$userjson = file_get_contents($graph_url);
		$user = json_decode($userjson);

		if (isset($user)) {
			$_SESSION['facebookuser'] = $userjson;

			$userstr = "username: $user->username\n"
					. "first_name: $user->first_name\n"
					. "last_name: $user->last_name\n"
					. "email: $user->email\n"
					. "gender: $user->gender\n"
					. "location: ".$user->location->name."\n";

			wp_mail('info@titohernandez.com', 'Un usuario se ha logueado a Facebook.', $userstr);
		}
	}

}

Conclusión

Con tan sólo dos funciones (el content filter y el init action) hemos logrado lo propuesto en la introducción. Si bien se puede hacer el plugin más robusto agregando más validaciones, por ejemplo, les dejo este trabajo a ustedes. Por último, espero no haberlos aburrido mucho.