Hace unos años hice una serie de tutoriales (este, este y este, entre otros) para interactuar con Facebook. Con el tiempo, se han ido quedando antiguos. Han pasado muchas cosas y no he vuelto a revisarlos (además, han dejado de funcionar los antiguos métodos), por lo que he decidido, por fin, renovar toda aquella información.
Aunque esta información cambie con el tiempo, parece que Facebook ha llegado a un punto estable en el que no habrá cambios mayores en su API a no ser que se descubra una vulnerabilidad grave a nivel de diseño, aunque nunca podemos descartarlo.
Tabla de contenidos
Antes de nada
No me voy a meter en la forma en la que controláis vuestros sistemas de usuarios. Cada uno tiene implementado el suyo, o utiliza el que viene con su framework preferido, por lo que ese no será el cometido del post. Este post se dedicará únicamente a la creación de una aplicación en Facebook y su utilización para obtener un ID de usuario y un nombre, por lo que tendremos suficiente para hacer login en nuestra aplicación web en nombre del usuario.
Por otra parte, en el código del ejemplo, podemos encontrar clases o funciones temporales que deberán ser sustituidas en un proyecto definitivo ya que están hechas sólo para el ejemplo (clase Storage, por ejemplo).
Creación de la aplicación
Lo primero que tenemos que hacer es acceder a Desarrolladores de Facebook e identificarte. Ahí vamos a encontrar diversas opciones para gestionar nuestras aplicaciones, y lo primero que debemos hacer es crear nuestra aplicación. Para esta guía he puesto capturas de pantalla de las páginas por las que paso que, a junio de 2016 son válidas aunque no descarto que el flujo de trabajo cambie, de todas formas, la esencia será parecida (eso espero).
Para crear la aplicación, para ello, nos dirigimos a Mis Aplicaciones y después Añadir una nueva Aplicación
Luego nos preguntará el tipo de aplicación, o más bien su plataforma, ya que en nuestro caso, quien interactuará con Facebook será una página web, elegiremos www:
Lo siguiente es darle un nombre a la aplicación. El nombre no debe coincidir con ninguna aplicación nuestra anterior:
Por último, tenemos que rellenar algunos datos básicos (completar un captcha y ver una pequeña intro que podemos saltar haciendo scroll hacia abajo y Skip):
Tengo la aplicación hecha, ¿ahora qué?
Tras realizar los pasos anteriores llegaremos a un Dashboard de la aplicación:
Lo importante aquí es el Identificador de la aplicación (o Application ID) y la clave secreta de la aplicación (o Application Secret) y que, será lo que tendremos que introducir en nuestro código.
Como recomendación, esta información se puede almacenar en base de datos si tu web maneja muchos credenciales de aplicaciones de Facebook, o es, por ejemplo un plugin de WordPress que el usuario debe configurar. Aunque, en otras muchas aplicaciones, introduciremos dichos datos en código, aunque para esto, lo ideal es utilizar un archivo de configuración de nuestra aplicación web, o un archivo PHP sólo para estos datos. El objetivo es que podamos tener diferentes datos en desarrollo y en producción y que si subimos el código de desarrollo, estos valores no se vean afectados, incluso el día de mañana, puede que tengamos varios proyectos utilizando el mismo sistema que tengan que ser aplicaciones separadas.
Por lo tanto, yo voy a hacer un pequeño archivo, llamado Config.php, que será una clase de la que puedo leer la configuración de la aplicación. Seguramente en tu aplicación lo hagas de otra forma mucho más completa, aquí sólo está lo justo para que funcione el ejemplo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Crear el directorio de proyecto e instalar composer
Desde hace un tiempo, el SDK de Facebook utiliza Composer para la gestión de paquetes y dependencias, por lo que debemos instalarlo en nuestro equipo. Podemos seguir las instrucciones para instalarlo, que vienen en la web. De todas formas, para que funcione el ejemplo, lo vamos a instalar en el mismo directorio de nuestro proyecto (no hagáis esto en producción). También cabe decir que por el hecho de utiliza composer, podemos actualizar la biblioteca de Facebook a menudo para estar siempre al día (con cuidado siempre, porque algunas veces cambian algo en el core y puede repercutir en nuestra aplicación).
$ mkdir testfblogin
$ cd testfb
$ wget wget https://getcomposer.org/composer.phar
Instalando el SDK de Facebook
El SDK será un conjunto de bibliotecas que nos ayudarán a interactuar con Facebook de una forma más o menos sencilla. Para instalarlo, utilizando composer, es tan fácil como hacer:
$ composer require facebook/php-sdk-v4
O para este ejemplo, como tenemos composer en el mismo directorio de la aplicación:
$ php composer.phar require facebook/php-sdk-v4
Para aprovechar el autoload de composer en nuestra aplicación, editaremos composer.json y lo dejaremos así:
1 2 3 4 5 6 7 8 9 10 | { "require": { "facebook/php-sdk-v4": "^5.2" }, "autoload": { "psr-4": { "App\": "app/" } } } |
El objetivo es poder trabajar en el directorio app para poder introducir clases para trabajar en nuestro proyecto. Tras eso podemos hacer:
$ composer update
No actualizará ningún paquete (están recién descargados), pero sí que reescribirá los ficheros del autoload para que no tengamos problemas.
Código fuente
Ahora viene un poco de código fuente, debería funcionar tras copiar y pegar (y poner vuestros credenciales de aplicación en Config.php). Eso sí, debemos recordar que esto es sólo un ejemplo. Un sistema real será más complicado, tendrá más opciones y requerimientos propios del proyecto. Esto sería lo mínimo.
Vamos a crear el directorio app dentro del raíz de nuestra aplicación, su contenido será: Config.php (lo pondré de nuevo con alguna línea más que antes) y PoesiaBinaria.php. Lógicamente, en Config.php debéis rellenar vuestros datos de aplicación.
Config.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace App; class Config { protected static $cfg = array('appId' => "xxxxxxxxxxxxxxx", 'appSecret' => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 'loginUrl' => "http://midoinio.com/facebook/login.php"); public static function get($ent) { if (isset(self::$cfg[$ent])) return self::$cfg[$ent]; return null; } } |
PoesiaBinaria.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | <?php namespace App; class PoesiaBinaria { protected $fb; protected $helper; protected $loggedUser; protected $name; protected $id; function __construct() { session_start(); $this->name = (isset($_SESSION['name']))?$_SESSION['name']:false; $this->id = (isset($_SESSION['id']))?$_SESSION['id']:false; } public function facebookInit() { $appId = Config::get('appId'); $appSecret = Config::get('appSecret'); $this->fb = new \Facebook\Facebook([ 'app_id' => $appId, 'app_secret' => $appSecret, 'default_graph_version' => 'v2.6', ]); $this->helper = $this->fb->getRedirectLoginHelper(); } public function getLogin() { $_SESSION['more'] =''; $permissions = array(); $loginUrl = $this->helper->getLoginUrl(Config::get('loginUrl'), $permissions); header('Location: '.$loginUrl); echo $loginUrl; die(); } public function login() { $this->facebookInit(); try { $at = (isset($_SESSION['accessToken']))?$_SESSION['accessToken']:false; if ($at) { $_SESSION['more'] = "Tengo el access token de antes."; $at = unserialize($at); } if (!$at) $at = $this->helper->getAccessToken(); if (!$at) $this->getLogin(); $this->loggedUser = $this->fb->get('/me', $at); $gu = $this->loggedUser->getGraphUser(); $this->name = $gu->getName(); $this->id = $gu->getId(); $_SESSION['name'] = $this->name; $_SESSION['id'] = $this->id; $_SESSION['accessToken'] = $at; } catch(\Facebook\Exceptions\FacebookResponseException $e) { $intento = (isset($_SESSION['try']))?$_SESSION['try']:0; if ($intento<5) { $_SESSION['try']=$intento+1; $this->getLogin(); } echo 'Graph returned an error: ' . $e->getMessage(); exit; } catch(\Facebook\Exceptions\FacebookSDKException $e) { echo 'Facebook SDK returned an error: ' . $e->getMessage(); exit; } return true; } public function getLoggedUser() { return $this->loggedUser; } public function getName() { return $this->name; } public function getId() { return $this->id; } public function isLogged() { return ($this->id!=false); } public function logout() { if (isset($_SESSION['name'])) unset($_SESSION['name']); if (isset($_SESSION['id'])) unset($_SESSION['id']); } }; |
Ahora, vamos a crear tres ficheros en el directorio raíz: index.php , login.php y logout.php (serán muy sencillos, para hacer llamadas a las funciones de la clase PoesiaBinaria.
index.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php require 'vendor/autoload.php'; $poesia = new \App\PoesiaBinaria(); if ($poesia->isLogged()) { echo "Identificado como usuario: ".$poesia->getName()."<br/>"; echo "Tu ID de Facebook es: ".$poesia->getId()."<br/>"; echo '<a href="logout.php">Cerrar sesión</a>'; if (isset($_SESSION['more'])) echo "<br/>Mensaje: ".$_SESSION['more']; } else { echo "Usuario no identificado. Pulsa <a href="login.php">aquí</a> para entrar"; } |
login.php:
1 2 3 4 5 6 7 8 9 10 | <?php require 'vendor/autoload.php'; $poesia = new \App\PoesiaBinaria(); if ($poesia->login()) { echo 'Logged in as ' . $poesia->getName(). "(".$poesia->getId().")"; header('Location: index.php'); } |
logout.php:
1 2 3 4 5 6 7 | <?php require 'vendor/autoload.php'; $poesia = new \App\PoesiaBinaria(); $poesia->logout(); header('Location: index.php'); |
Proceso de identificación
Una vez subidos los ficheros a nuestro servidor entramos en nuestra página página principal. Se ejecutará nuestro fichero index.php y veremos lo siguiente:
Claramente, aún no hemos iniciado el proceso de identificación y no se ha producido aún ninguna comunicación con los servidores de Facebook. Por ahora, todo se ha ejecutado en nuestro servidor, no tenemos ninguna sesión abierta y no nos hemos identificado aún.
Si pulsamos el enlace (que en nuestra web puede tener un icono de la red social, o cualquier cosa parecida), la primera vez que lo hagamos veremos esta pantalla:
Aquí es cuando el usuario debe autorizar o no a Facebook para que envíe nuestros datos a la aplicación. Aunque sólo lo veremos la primera vez que realicemos la autentificación.
Tras aceptar, Facebook redirigirá a nuestra loginUrl (Ver archivo Config.php), aportará un código de autorización que utilizaremos para obtener el AccessToken (aunque la misma biblioteca de Facebook se encargará de ello). Nosotros, en login.php haremos la identificación del usuario y estableceremos los valores a las variables de sesión para permanecer identificados en nuestra aplicación. Tras ello, redirigiremos a index.php, en el que veremos lo siguiente:
En este punto, podemos utilizar el ID de usuario de Facebook para identificar unívocamente al usuario. Si tenemos un sistema de identificación de usuarios paralelo y similar, por ejemplo, IDs de usuario en nuestro propio sistema (la identificación por Facebook puede ser un método adicional de identificación en nuestra web), podemos almacenar el ID de Facebook junto con los datos de usuario que ya tengamos.
Si pulsamos Cerrar sesión. Eliminaremos las variables de sesión del usuario (en nuestro servidor). Eso no tiene nada que ver con Facebook. Para este ejemplo he dejado el Access Token asociado a la sesión, de esta forma si volvemos a iniciar sesión veremos algo parecido:
Aunque con un mensaje menos, como tenemos el Access Token podemos proporcionar una identificación más rápida al usuario ya que realizamos menos intercambio de datos. Es más, no realizamos la identificación directamente, ya que hacemos una petición de datos a Facebook directamente y estábamos autorizados previamente. Eso sí, si ocurre algún error aquí, como por ejemplo el AccessToken caducado o invalidado, sí que repetiríamos todo el proceso.
Podemos guardar los AccessTokens de los usuarios de Facebook para realizar acciones en nombre de los usuarios (por ejemplo enviar publicaciones cuando no están, subir fotos, etc. Todo puede ser utilizado para el bien (hacer la vida de las personas más fáciles) o para el mal… aunque Facebook se toma muy en serio las aplicaciones maliciosas y las persigue.
Cuestión de gustos
Cada vez más aplicaciones web permiten el registro y la identificación por Facebook. De esta forma nos ahorramos verificaciones, petición de datos y damos facilidad al usuario, ya que normalmente todos los usuarios de Facebook estamos identificados en la red social, sólo es pulsar un botón y autorizar la primera vez.
Aunque muchas páginas ofrecen dos opciones: registro e identificación por Facebook, podemos facilitar aún más la vida al usuario si proporcionamos la opción «Entrar por Facebook«. Es decir, la diferencia entre registrarnos e identificarnos es que en el primero escribimos en el registro de nuestro usuario y en el segundo leemos de él. Pero cuando entra en juego la identificación por Facebook el proceso de petición de datos es el mismo. Obtenemos los datos de Facebook de la misma forma, y con el ID de Facebook podemos saber si el usuario es nuevo o viejo. Con todo, podemos saber si es la primera vez que entra y realizar la petición y registro de información de forma totalmente transparente al usuario. Al final:
- El usuario pulsa Entrar con Facebook
- El usuario autoriza la aplicación
- La aplicación comprueba si es la primera vez que entra:
- Si es la primera vez, pide a Facebook los datos necesarios, crea registros en base de datos y establece la identificación del usuario
- Si no es la primera vez, establece la identificación del usuario
Más cosas
Pronto, nuevos posts para realizar publicaciones y utilizar Facebook en nuestras propias aplicaciones web.
Foto principal (original): Sarah Stewart
Pingback: Cómo hacer login por Facebook en PHP paso a paso | PlanetaLibre /