¿Cómo usar LightopenID para identificar en nuestra web a los usuarios con sus cuentas de Google, Yahoo!...?

Cuando desarrollamos una web la mayoría de las veces sólo nos interesa saber si el usuario está logeado o no para poder escribir comentarios, votar... Desarrollar un sistema de identificación es muy crítico, debido al manejo de datos tan importantes como las contraseñas o emails.

¡Pues una solución genial es usar openID!

¿Qué es openID como usuario de una web? Pues digamos que tienes una cuenta de Gmail, pues te identificas en una web con esa cuenta y ya quedas identificado, evitando tener que registrarte mil veces para mil webs. Existen varios proveedores de openID, como Google, Yahoo!, Flickr... ¡y con ellos ya tienes una cuenta openID!

¿Qué es openID como servidor (web)? Una manera de evitar almacenar y gestionar información muy confidencial y crítica, y evitar al usuario la tediosa tarea de registro, usando para ella su cuenta openID.

¿Cómo implemento openID en mi web (servidor)? Hay múltiples librerías para distintos lenguajes que facilitan el uso de openID.
En mi caso voy a usar LightOpenID para PHP. Copiamos la librería openid.php en el directorio junto a los siguientes ficheros que crearemos en el mismo directorio:

login.php: Primer fichero para logearnos, mostrará los proveedores como un enlace, ponerlo guapo ya es tarea tuya ;)
<?php
session_start();
if (isset($_SESSION['logueado'])) {
    echo "Logueado";
}
else
{
    require_once 'openid.php';
    $openid_google = new LightOpenID("http://tu_servidor.com");
    $openid_google->identity = 'https://www.google.com/accounts/o8/id';
    $openid_google->returnUrl = 'setID.php';
   
    $openid_yahoo = new LightOpenID("http://tu_servidor.com");
    $openid_yahoo->identity = 'http://me.yahoo.com/';
    $openid_yahoo->returnUrl = 'setID.php';
}
?>
<a href="<?php echo $openid_google->authUrl() ?>">Entrar con cuenta de Google</a>
<a href="<?php echo $openid_yahoo->authUrl() ?>">Entrar con cuenta de Yahoo!</a>


El código en verde lo explicaré más adelante, lo que nos importa ahora es el naranja. Definimos cada proveedor de openID que queremos usar y creamos un enlace que al pulsarlo invocará una web externa con el proveedor, por ejemplo Google, que si damos el permiso llamará al fichero siguiente (especificado por $openid_google->returnUrl) en nuestro servidor.



setID.php: Es el fichero que recibe la respuesta del proveedor de openID (por ejemplo Google, Yahoo!, myOpenID...) tras login.php:
<?php
session_start();
require_once 'openid.php';
$openid = new LightOpenID("http://tu_servidor.com");
 if ($openid->mode) {
    if ($openid->mode == 'cancel') {
        echo "Cancelado";
    } elseif($openid->validate()) {
        $_SESSION['logueado'] = $openid->identity;
        echo "logueado";
    } else {
        echo "No logueado";
    }
}
else
{
    echo "No vienes desde login.php";
}
?>

Aquí comprobamos qué nos devolvió el proveedor de openID (por ejemplo Google) y devolvemos un resultado al cliente, sería ideal por ejemplo invocar la página principal automáticamente con una redirección PHP.


logout.php: Para desloguearnos creamos un fichero que contendrá lo siguiente:
<?php
session_start();
session_destroy();
echo "No Logged";
?>

No hay nada naranja :P Cierto, aquí ya no interviene openID.


Resumiendo, como veis usar openID con LightOpenID es relativamente sencillo. Pero atención, identificarnos genera un identificador que proviene del proveedor de openID ($openid->identity) y es una cadena única que nos identifica, ¡pero se pierde! tras salir de setID.php. ¿Cómo saber si estamos logueados en las siguientes páginas? Pues creamos una sesión PHP con la que sabremos si estamos logueados o no (y es el código que está en verde). En login.php no ejecutamos ningún código si ya estamos logueados, en setID.php establecemos la sesión PHP y en logout.php la destruimos.

Resumiendo: Un sistema standard, eficaz, limpio, poco intrusivo y claro para identificar usuarios :)

Se pueden obtener datos como el email o nombre de usuario en algunos casos (devueltos por el proveedor en formato JSON) y jamás podremos obtener la contraseña del usuario.

Podemos usar selectores con jQuery para hacer un formulario mucho más vistoso, como jQuery openID Simple.

Las URLs para más proveedores son:
  • Google: https://www.google.com/accounts/o8/id
  • Yahoo: http://me.yahoo.com/
  • AOL: http://openid.aol.com/{usernam}
  • MyOpenID: http://{username}.myopenid.com/
  • LiveJournal: http://{username}.livejournal.com/
  • flickr: http://flickr.com/{username}/
  • technorati: http://technorati.com/people/technorati/{username}/
  • WordPress: http://{username}.wordpress.com/
  • Blogger: http://{username}.blogspot.com/
  • Verising: http://{username}.pip.verisignlabs.com/
  • vidoop: http://{username}.myvidoop.com/
  • launchpad: https://launchpad.net/~{username}
  • ClaimID: http://claimid.com/{username}
  • clickpass: http://clickpass.com/public/{username}
  • Google Profile: http://www.google.com/profiles/{username}

Enlace con buena explicación: JAlvB.


10 comments:

  1. hola amigo estoy utilizando esta librería, muy buena tu explicación para el caso que presentas. Tengo problemas al llamar a la librería desde un index.php que tengo en otro dominio, es decir mi index.php esta en contactos.se.pe y openind esta en lib.se.pe se hiso esto con el objetivo de estandarizar el uso de esta librería y todas las aplicaciones la puedan utilizar, cuando redirijo a lib.se.pe me sale el error de request parse OpenId, como si no podria redirigi de un dominio a otro.

    ReplyDelete
  2. haber si me puedes ayudar con este error te explico mas a detalle, cual es la lógica.

    ReplyDelete
  3. Hola, si no me equivoco, openID te identifica contra un dominio en particular. Imagina que te logueas en google.com y luego vas a yahoo.com y no estás logueado, ¿lógico no? :)

    Para tu problema en particular creo que te valdría implementar el equivalente a los famosos checkbox "Recordarme", que cuando cierras el navegador y vuelves a entrar sigues logueado ;) Mediante cookies puedes saber si cada usuario está logueado en contactos.se.pe y si lo está, al principio de lib.se.pe simplemente lo das como logueado, sin llamar a openID.
    Busca en google cookies recordar sesión y tienes buenos manuales e incluso el código :)
    http://www.bitacoralinux.es/recordar-usuario-y-contrasena-con-cookies/

    Un saludo y espero haberte ayudado.

    ReplyDelete
  4. Hola Marcos primero que nada gracias por responder, mira te dejo el código de mi index.php donde tengo las referencias.

    require_once '../lib/google_login/openid.php';
    $login_google='https://www.google.com/accounts/o8/id';

    $openid = new LightOpenID('http://contactos.se.pe');

    $openid->identity = $login_google;
    $openid->required = array(
    'namePerson/first',
    'contact/email',
    'contact/country/home',
    );
    $openid->returnUrl = "http://lib.semanaeconomica.com/google_login/libreria.php"

    luego el boton que tiene el metodo authUrl

    /**************/
    el resultado que quiero conseguir con eso es que dea permiso de logueo a contactos.se.pe pero de acuerdo a criterios que tengo en lib.se.pe en el archivo libreria.php es donde tengo la validación del usuario y la dirección de acuerdo a privilegios, el error que obtengo con eso es el siguiente:
    Error:invalid_request

    Error in parsing the OpenID auth request


    ReplyDelete
  5. para mi caso el archivo libreria.php seria en tu caso SetID.php, el archivo openid.php tmb esta en lib.semanaeconomica.com. lo que queremos con esto es hacer de opeinid y libreria.php una libreria para todas las aplicaciones y evitar el hardcode. por eso es que se requiere que estea en un dominio diferente al de las aplicaciones.

    ReplyDelete
  6. Marcos creo que ya logre solucionar el error estableciendo como dominio a lib.semaneconomica.com y el return al mismo dominio, y ya me da acceso a formulario de login de google, pero ahora el problema es que no mantiene la sesión entre dominios y mi pagina index me sale sin ningún tipo de restricciones del usuario

    ReplyDelete
  7. Genial.
    Cuando dices que no tienes restricciones, recuerda que si estás logueado ya no te saldrá el loguearte ;)

    Lo de mantener sesión entre dominios tendrías que hacerlo mediante cookies.

    Te dejo código de mi proyecto openMarkers (openmarkers.tuxfamily.org), donde tuve que pelearme precisamente con openID y mantener las sesiones abiertas para cuando el usuario vuelve a entrar (en tu caso, cuando viene y va de un dominio a otro):
    http://bazaar.launchpad.net/~costales/openmarkers/trunk/files/141

    La chicha la tienes aquí:
    http://bazaar.launchpad.net/~costales/openmarkers/trunk/files/head:/API/openID/
    y más concretamente aquí, en la línea 13 si está identificado, reenvío a la página a la que quiere acceder sin meterle el popup de identificación :)
    http://bazaar.launchpad.net/~costales/openmarkers/trunk/view/head:/API/openID/login.php

    ReplyDelete
  8. gracias por responder una ves mas Marcos. la verdad que el código que me enviaste esta bastante avanzado y no lo entiendo, por favor podrías darme un ejemplo de como implementarlo, te muestro actualmente como esta funcionando. el index.php.

    require_once '../lib/google_login/openid.php';
    $openid = new LightOpenID('http://lib.semanaeconomica.com');
    $openid->identity ='https://www.google.com/accounts/o8/id';
    $openid->required = array(
    'namePerson/first',
    'contact/email',
    'contact/country/home',
    );
    $openid->returnUrl = "http://lib.semanaeconomica.com/google_login/libreria.php";


    de esta forma se elimina el error que obtenía, pero ahora en libreria.php tengo lo siguiente:

    require ('openid.php');
    $urls="http://lib.semanaeconomica.com";
    $openid = new LightOpenID("http://lib.semanaeconomica.com");


    f ($openid->mode) {

    if ($openid->mode == 'cancel') {

    echo "Error: User has canceled authentication ! Please go back to the index page to try again";

    } elseif($openid->validate()) {

    $data = $openid->getAttributes();

    $email = $data['contact/email'];
    $first = $data['namePerson/first'];
    $homecountry = $data['contact/country/home'];

    $_SESSION['email'] = $email;
    $_SESSION['firstname'] = $first;
    $_SESSION['home'] = $homecountry;
    $usuario=$_SESSION['email'];


    $db = new mysqldb();
    $db->select_db_usuarios();//conexion a la BD usuarios

    $sql_privilegios=("select * from usuario where identificador_usuario='".$_SESSION['email']."' and url_libreria='$urls' ");

    $result_usuario=$db->query($sql_privilegios);



    while ($row = mysql_fetch_array($result_usuario)) {


    $id = $row['id_usuario'];
    $rol=$row['rol_usuario'];
    $identificador=$row['identificador_usuario'];
    $nombre_usuario=$row['nombres_usuario'];
    $rol_usuario=$row['rol_usuario'];
    $apellido_usuario=$row['apellidos_usuario'];
    $url_global=$row['url_global'];
    $url_por_rol=$row['url_por_rol'];
    // $_SESSION['']$url_global=$row['url_global'];
    $_SESSION['rol_usuario']=$rol_usuario;
    $_SESSION['url_global']=$url_global;

    $result_num=$db->num_rows($result_usuario);

    if(($result_num)>0){

    header('Location: cuenta.php');

    }elseif($result_num==0){


    echo'No se obtuvieron datos para este usuario');



    hasta alli bien, ahora cuando la consulta arroja que existe un usuario en la BD entonces direcciona a cuenta.php que contiene lo siguiente:

    esta url donde manejo y dibujo los menús de acuerdo al rol del usuario, y creo que aqui es donde se pierde la sesión al rutear al dominio contactos.se.pe/dashboard.php porque me sale esa pagina pero solo con datos estáticos es decir imágenes, css.

    este es el link que le paso si el usuario tiene algun rol:
    $url_1='http://contactos.se.pe/dashboard.php';

    ReplyDelete
  9. Hola Marcos, del alguna forma resolvi el problema que te comente, dime porfavor como puedo cerrar la sesion del todo, tengo el problema que cuando cierro sesion con esto que encontre en internet mail.google.com/mail/?logout me envia a la pagina de logout de google pero si le doy la flecha atras del navegador me regresa donde estaba antes de cerrar sesion. com puedo destruir totalmente la sesion.

    ReplyDelete
  10. Hola Jose, simplemente con:
    session_start();
    session_destroy();
    Ya cierras la sesión.

    Posiblemente cuando das para atrás la has cerrado, pero estas recargando la caché del navegador ¿? Pulsa F5 o realiza alguna acción que requiera estar registrado para saber que realmente está deslogueado ;)

    ReplyDelete