Ejemplo de OAuth en KumbiaPHP

De KumbiaPHP Framework Wiki
{{#if:Import.png |}} {{#if: |}}



Introducción

Nota previa Este ejemplo fue tomado de la documentación oficial de Twitter / TwitterOAuth y adaptado a la arquitectura MVC de KumbiaPHP de forma básica.

Se ha vuelto común ver sitios webs que ofrecen sus servicios para usuarios utilizando métodos de autenticación bastante convencionales como OAuth, OpenID, etc. para este ejemplo el enfoque estará sobre OAuth.


Requisitos

Como este ejemplo se basa en twitter es primordial tener una cuenta creada en este sistema de bloging, si aún no tienes ya es hora que te registrates en Twitter. y seas un seguidor(followers) de @KumbiaPHP

Descargar la librería TwitterOAuth, descomprimela y copia los ficheros OAuth.php y TwitterOAuth.php en /app/libs/ de tu arbol de directorios de KumbiaPHP. Importante: La librería TwitterOAuth necesita que el PHP del servidor tenga soporte para las funciones de cURL.


Registra también tu aplicación, indicando que es de tipo de aplicación Navegador (Browser), indica el tipo de permiso que necesitas (ReadOnly o ReadWrite), y marca el checkbox final, para indicar que usaremos Twitter para hacer inicios de sesión.

Pasos previos

Debido a un problema de desbordamiento de entero en la funcion json_decode(), hay que parchear la librería TwitterOAuth para que los id de los mensajes se traten correctamente.

Editar el fichero TwitterOAuth.php y sustituir

      return json_decode($response);

por

      return json_decode(preg_replace('/"id":(\d+)/', '"id":"$1"', $response));

en las funciones get(), post() y delete(). Este fallo ya era conocido por Abraham, el desarrollador de TwitterOAuth y le pasé el "parche" para que lo tuviera en cuenta. Aquellos que tengais PHP 5.3 podeis usar el parametro JSON_BIGINT_AS_STRING en la funcion json_decode(), quedando así:

       return json_decode($response, false, 512, JSON_BIGINT_AS_STRING));


Pasos

creamos un controlador, usando el codigo de la documentación de TwitterOAuth como base: app/controllers/oauth_controller.php

<?php
Load::lib("TwitterOAuth");
class OAuthController extends AppController 
{
	protected $consumerKey;
	protected $consumerSecret;
	protected $callBack;

	public function before_filter() {
                /* Esto es mio, ya que tengo los valores en la base de datos, lo dejo para servir de ejemplo
		$rows = $this->Configuration->find("name LIKE '%oauth%' ORDER BY name ASC");
		$this->callBack 	= $rows[0]->value;
		$this->consumerKey 	= $rows[1]->value;
		$this->consumerSecret	= $rows[2]->value;
                */
                $this->callBack 	= "http://<tudominio>/oauth/_callback";
		$this->consumerKey 	= "<aqui tu Consumer Key>";
		$this->consumerSecret	= "<aqui tu Consumer Secret>";
	}
		
	public function index() 
	{
		session_start();
		if (empty($_SESSION['access_token']) || empty($_SESSION['access_token']['oauth_token']) || empty($_SESSION['access_token']['oauth_token_secret'])) 
		{
			View::select(NULL, NULL);
			return Router::redirect("oauth/_register");
		}

		/* Get user access tokens out of the session. */
		$access_token = $_SESSION['access_token'];

		/* If access tokens are not available redirect to connect page. */
		if (empty($access_token['oauth_token']) || empty($access_token['oauth_token_secret'])) {
			header('Location: http://<tudominio>/oauth/_register/');
		}

		/* Create a TwitterOauth object with consumer/user tokens. */
		$connection = new TwitterOAuth($this->consumerKey, $this->consumerSecret, $access_token['oauth_token'], $access_token['oauth_token_secret']);

		/* Get credentials to test API access */
		$credentials = $connection->get('account/verify_credentials');
 
		if ($credentials->error) {
			$this->msg = $credentials->error."<br><br><a href='http://<tudominio>/oauth/_register'>Register now</a>";
		}
		else {
			$this->msg = "Acceso confirmado, OAuth correcto. Bienvenido ".$credentials->screen_name.".<br><br><a href='http://<tudominio>/oauth/_logout'>Logout</a>";
		}
	}

	public function _redirect() 
	{
		session_start();

		/* Create TwitterOAuth object and get request token */
		$connection = new TwitterOAuth($this->consumerKey, $this->consumerSecret);

		/* Get request token */
		$request_token = $connection->getRequestToken($this->callBack);

		/* Save request token to session */
		$_SESSION['oauth_token'] = $token = $request_token['oauth_token'];
		$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];
		 
		/* If last connection fails don't display authorization link */
		switch ($connection->http_code) {
			case 200:
				/* Build authorize URL */
				$url = $connection->getAuthorizeURL($token);
				header('Location: ' . $url);
				break;
			default:
				echo 'Could not connect to Twitter. Refresh the page or try again later.';
		}
		die();
	}

	public function _register() {
		session_start();
		session_destroy();
	}

	public function _logout() {
		session_start();
		session_destroy();
	        View::select(NULL, NULL);
	        return Router::redirect("oauth/index");
	}

	public function _callback() 
	{
		session_start();

		/* If the oauth_token is old redirect to the connect page. */
		if (isset($_REQUEST['oauth_token']) && $_SESSION['oauth_token'] !== $_REQUEST['oauth_token']) {
			$_SESSION['oauth_status'] = 'oldtoken';
			header('Location: http://<tudominio>/oauth/_register/');
		}

		/* Create TwitteroAuth object with app key/secret and token key/secret from default phase */
		$connection = new TwitterOAuth($this->consumerKey, $this->consumerSecret, $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);

		/* Request access tokens from twitter */
		$access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']);

		/* Save the access tokens. Normally these would be saved in a database for future use. */
		$_SESSION['access_token'] = $access_token;

		/* Remove no longer needed request tokens */
		unset($_SESSION['oauth_token']);
		unset($_SESSION['oauth_token_secret']);

		/* If HTTP response is 200 continue otherwise send to connect page to retry */
		if (200 == $connection->http_code) {
			/* The user has been verified and the access tokens can be saved for future use */
			$_SESSION['status'] = 'verified';
			header('Location: http://<tudominio>/oauth/index/');
		} else {
			/* Save HTTP status for error dialog on connnect page.*/
			header('Location: http://<tudominio>/oauth/_register/');
		}
		die();
	}

}
?>


Por último, creamos las vistas: views/oauth/index.phtml:

<?php echo $msg; ?>

views/oauth/_register.phtml:

<a href="http://<tudominio>/oauth/_redirect/"><img src="/img/lighter.png" alt="Sign in with Twitter"/></a>

Pruebas

Ya esta! Ahora ya puedes visitar la URL de tu controlador en http://<tudominio>/oauth y probarlo. La primera vez se te pedirá autorizar a la aplicación, pero una vez hecho, ya no hará falta.

Puedes hacer distintas pruebas:

  1. Cerrar la sesion de Twitter, cerrar el navegador, abrirlo y acceder a tu controlador. Veras que se te muestra el botón de iniciar sesión. Como la aplicación ya está autorizada, sólamente debes iniciar sesión en Twitter y se redirige de nuevo a tu controlador.
  2. Cerrar el navegador, iniciar Twitter y luego acceder a tu controlador. Se te muestra de nuevo el botón de iniciar sesión. Como la aplicación está autorizada y ya has iniciado sesión en Twitter, el inicio de sesión es automático sólo con pulsar el botón.


Links


Para cualquier duda, podeis enviarme un email o buscarme por el IRC.

Saludos,

Soukron