Estamos trabajando en algo propio llamado KODOTI. Click para unirte
Se viene KODOTI. Únete

Implementación de Json Web Token con PHP

En esta entrada vamos a poner en práctica la autenticación con un ejemplo en PHP.

Rodríguez Patiño, Eduardo
45,828 lecturas
Rodríguez Patiño, Eduardo
Hemos migrado hace poco nuestras publicaciones del blog antiguo. Si crees que esta se encuentra incompleta o sin coherencia deja un comentario para restaurarla manualmente.

En este ejemplo práctico vamos a autenticar a un usuario usando Json Web Token. Para esto debemos agregar la dependencai mediante Composer.

composer require firebase/php-jwt

Generando nuestro Token

Para implementar facilmente nuestro JWT vamos a crear el siguiente script:

require_once 'vendor/autoload.php';

use Firebase\JWT\JWT;

$time = time();
$key = 'my_secret_key';

$token = array(
    'iat' => $time, // Tiempo que inició el token
    'exp' => $time + (60*60), // Tiempo que expirará el token (+1 hora)
    'data' => [ // información del usuario
        'id' => 1,
        'name' => 'Eduardo'
    ]
);

$jwt = JWT::encode($token, $key);

$data = JWT::decode($jwt, $key, array('HS256'));

var_dump($data);

No es nada del otro mundo así que no se asusten

  • JWT::encode recibe 2 parámetros, el primero es la información que queremos que contenga nuestro token y el otro es una cadena que usaremos como key para evitar que otro pueda decodificar nuestro token.
  • La información que contendrá nuestro token esta compuesto por un par de parámetros.
    • iat: es el tiempo que el token inició
    • exp: es el tiempo que el token expirará, por defecto le hemos puesto del tiempo que inicio una hora más.
    • data: es información que queremos que guarde el token, en nuestro caso la información del usuario.
    • Si corrieron el script y no hubo problema alguno deberán visualizar la siguiente información.
object(stdClass)[3]
  public 'iat' => int 1456170718
  public 'exp' => int 1456174318
  public 'data' => 
    object(stdClass)[4]
      public 'id' => int 1
      public 'name' => string 'Eduardo' (length=7)

Validando el Token

Al momento de intentar decodificar el token hubiera algún problema de validación una excepción será arrojada. Para este caso vamos hacer 2 pruebas para arrojar la excepción.

Secret Key incorrecto

En esta prueba, el key ingresado para decodificar el token no es el mismo que se usó para codificarlo.

$jwt = JWT::encode($token, $key);
$data = JWT::decode($jwt, 'SOY OTRO KEY', array('HS256'));

La excepción sería la siguiente:

Signature verification failed

Excedimos el tiempo de expiración

En esta prueba vamos a restarle un segundo al tiempo de expiración.

$time = time();
$key = 'my_secret_key';

$token = array(
    'iat' => $time,
    'exp' => $time--,
    'data' => [
        'id' => 1,
        'name' => 'Eduardo'
    ]
);

$jwt = JWT::encode($token, $key);
$data = JWT::decode($jwt, $key, array('HS256'));

La excepción sería la siguiente:

Expired token

Haciendo la vida más sencilla

He creado una clase que permita trabajar de manera más práctica con JWT. Esta nos va a permitir generar el token, almacenar la información del usuario "data" y adicionalmente le agregará mayor seguridad para evitar que usen nuestro token en otro navegador. Por defecto el tiempo de expiración ha sido seteado a una hora.

<?php
use Firebase\JWT\JWT;

class Auth
{
    private static $secret_key = 'Sdw1s9x8@';
    private static $encrypt = ['HS256'];
    private static $aud = null;

    public static function SignIn($data)
    {
        $time = time();

        $token = array(
            'exp' => $time + (60*60),
            'aud' => self::Aud(),
            'data' => $data
        );

        return JWT::encode($token, self::$secret_key);
    }

    public static function Check($token)
    {
        if(empty($token))
        {
            throw new Exception("Invalid token supplied.");
        }

        $decode = JWT::decode(
            $token,
            self::$secret_key,
            self::$encrypt
        );

        if($decode->aud !== self::Aud())
        {
            throw new Exception("Invalid user logged in.");
        }
    }

    public static function GetData($token)
    {
        return JWT::decode(
            $token,
            self::$secret_key,
            self::$encrypt
        )->data;
    }

    private static function Aud()
    {
        $aud = '';

        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $aud = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $aud = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } else {
            $aud = $_SERVER['REMOTE_ADDR'];
        }

        $aud .= @$_SERVER['HTTP_USER_AGENT'];
        $aud .= gethostname();

        return sha1($aud);
    }
}

Ejemplo de autenticación

En nuestro flujo normal una vez validado nuestro usuario y password llamamos al método SignIn y le pasamos la información que queremos guardar, en nuestro la información del usuario. Luego este nos va a retornar el token asociado.

<?php
$usuario  = 'eduardo';
$password = '123456';
if($usuario === if($usuario === 'eduardo' && $password === '123456')
{
    echo Auth::SignIn([
        'id' => 1,
        'name' => 'Eduardo'
    ]);
}

Recuperando la data de nuestro usuario guardada en el token

Le pasamos el token generado y este nos retornará la información del usuario.

$token = $_GET['t'];

var_dump(
    Auth::GetData(
        $token
    )
);

LEEME

Estoy adjutando el ejemplo práctico para ello van a tener que jugar con la URL para poder hacer funcionar el ejemplo.

  1. Ejecutamos la siguiente ruta: index.php?p=autentica
  2. Este nos va a generar un TOKEN y copiamos dicho TOKEN para hacer las pruebas necesarias.
  3. Ejecutamos la siguiente ruta: index.php?p=verifica&t={token}
  4. Reemplazamos {token} por el valor que copiamos en el paso 1, si todo esta bien veremos la información de nuestro usuario que guardamos en el token.

Como dije, el uso de TOKEN requiere de mayor conocimiento. Si tienes duda déjame un comentario para responderte lo más pronto posible.

¿Te gustó nuestra publicación?
Suscríbete a nuestro boletín