logo cosasdedevs
Login con JWT en una api con Laravel 8

Login con JWT en una api con Laravel 8



My Profile
Mar 17, 2021

¡Hola! Después de un mes catastrófico en el que tuve mucho estrés, me pilló la gastroenteritis de mi vida y en el que cuando parece que empiezo a mejorar y puedo ponerme manos a la obra con un nuevo tuto hay un incendio en los data centers de OVH donde como podréis adivinar estaba alojado cosasdedevs (menos mal que tenía copia de seguridad de la base de datos), volvemos a la carga con muchas ganas de seguir trabajando en el blog y en nuevos proyectos que veréis más adelante 😁.

En este tutorial vamos a seguir profundizando en Laravel 8 y esta vez quiero realizar un tutorial que se dividirá en dos partes. En la primera parte, como habréis podido deducir del título 😁, aprenderemos a realizar el login con JWT y así obtener un token con el que podremos autenticarnos en las llamadas a nuestra API. En la segunda parte del tutorial, aprenderemos como crear un CRUD en nuestra API para gestionar los endpoints de esta.

Crear proyecto

La idea es que estos dos tutoriales estén conectados, pero puedan ser totalmente independientes el uno del otro, así que bien, podéis seguirlo buscando la forma de integrarlo en vuestros proyectos o podéis seguir el proyecto que yo voy a crear en el que vamos a crear una API para gestionar una aplicación en el que un usuario pueda subir fotos de sus perretes. Para ello, lo primero que haremos será crear el proyecto:

laravel new api-perretes-laravel

El siguiente paso es instalar la dependencia de JWT vía composer, para ello solo debemos lanzar el siguiente comando:

composer require tymon/jwt-auth

Configuración

Una vez instalado, debemos abrir el archivo config/app.php. Ahí veremos que retorna un array enorme. Pues bien, debemos ir a la clave providers y añadir la siguiente línea:

Tymon\JWTAuth\Providers\LaravelServiceProvider::class,

De tal forma que quedaría algo así:

'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        .
        .
        .
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,
        Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
        .
        .
        .
],

Al añadirlo en esta lista, el servicio de JWT se cargará automáticamente cada vez que un usuario haga una petición a nuestra API.

Una vez hecho esto, deberemos crear un archivo llamado config/jwt.php, para ello, solo debemos lanzar el siguiente comando y este lo creará automáticamente:

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

Una vez creado, lanzaremos el siguiente comando para crear una variable de entorno con una key para JWT. Lanzamos el siguiente comando y listo:

php artisan jwt:secret

Ahora deberemos modificar la forma en la que nos autenticamos por defecto en Laravel así que lo queremos hacer es abrir el archivo config/auth.php y sustituir unas claves y valores por los siguientes:

    .
    .
    .
    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
    ],
    .
    .
    .
    'guards' => [
        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
    ],

En la clave defaults lo que hacemos es sustituir guard con valor web por api, ya que el tipo de login que vamos a usar va a ser el de API.

En la clave guards, eliminamos la clave web, ya que no la necesitamos y en API le diremos que vamos a usar el driver de JWT.

Modelo

Una vez hecho esto, deberemos editar el modelo User.php que ya viene por defecto en Laravel, asi que abrimos el archivo app/Models/User.php y reemplazamos su contenido por el siguiente:

<?php

namespace App\Models;


use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements JWTSubject
{
    use Notifiable;

    // Rest omitted for brevity

    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}

Controlador

Para gestionar las peticiones de login, necesitaremos crear un controlador que se encargue de la autenticación. Para crearlo, lanzamos el siguiente comando:

php artisan make:controller Api/V1/AuthController

De esta forma, crearemos el controlador para gestionar la autenticación en la ruta app/Http/Controllers/Api/V1/AuthController.php. Una vez creado, añadiremos el siguiente código:

<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;

class AuthController extends Controller
{
    /**
     * Create a new AuthController instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['login']]);
    }

    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login()
    {
        $credentials = request(['email', 'password']);

        if (! $token = auth()->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);
    }

    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        return response()->json(auth()->user());
    }

    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout()
    {
        auth()->logout();

        return response()->json(['message' => 'Successfully logged out']);
    }

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        return $this->respondWithToken(auth()->refresh());
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth()->factory()->getTTL() * 60
        ]);
    }
}

Este código se encargará de gestionar las distintas rutas que utilizaremos para todo el proceso de autenticación.

Rutas

El siguiente paso que haremos, será configurar las rutas así abrimos el archivo routes/api.php y sustituimos su contenido por el siguiente:

<?php

use Illuminate\Support\Facades\Route;

Route::group([
    'middleware' => 'api',
    'prefix' => 'v1/auth'

], function ($router) {
    Route::post('login', [\App\Http\Controllers\Api\V1\AuthController::class, 'login'])->name('login');
    Route::post('logout', [\App\Http\Controllers\Api\V1\AuthController::class, 'logout'])->name('logout');
    Route::post('refresh', [\App\Http\Controllers\Api\V1\AuthController::class, 'refresh'])->name('refresh');
    Route::post('me', [\App\Http\Controllers\Api\V1\AuthController::class, 'me'])->name('me');
});

Como podéis ver, la dependencia de JWT en Laravel nos crea varias rutas aunque en nuestro caso solo utilizaremos la ruta de login para obtener el token de acceso.

También, todas nuestras rutas tendrán un prefijo v1/auth, de esta forma si luego trabajamos con otra versión, podremos separar como hacer la autenticación de una versión a otra.

Configuración de la BBDD

Como siempre, deberemos editar el archivo .env para añadir las conexiones a la base de datos así que lo abrimos y añadimos la configuración a nuestra bbdd. Os dejo la mía de ejemplo:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=api_perretes_laravel
DB_USERNAME=root
DB_PASSWORD=passultrasecreto

Recordad que tenéis que crear la base de datos con el nombre que queráis en vuestro cliente de MySQL para que todo funcione correctamente. En mi caso tuve que crear una bbdd llamada api_perretes_laravel.

El siguiente paso es crear unos cuantos usuarios para probar que todo funciona correctamente. Para ello, vamos al archivo database/seeders/DatabaseSeeder.php y descomentamos la línea para crear los usuarios. De esta forma podremos crearlos automáticamente cuando lancemos la migración de las tablas a la base de datos.

    public function run()
    {
        \App\Models\User::factory(10)->create();
    }

Una vez hecho esto, vamos a crear los usuarios y las tablas en la base de datos. Para ello lanzamos el siguiente comando:

php artisan migrate --seed

NOTA: Si os aparece el siguiente error:

PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes")

Deberéis ir al archivo app/Providers/AppServiceProvider.php, importar la clase Schema y modificar el método boot para que ahora contenga la siguiente línea:

use Illuminate\Support\Facades\Schema;

    public function boot()
    {
        Schema::defaultStringLength(191);
    }

Ahora lanzamos el migrate de nuevo pero esta vez con la extensión fresh para eliminar las tablas creadas anteriormente y así evitar conflictos:

php artisan migrate:fresh --seed

NOTA: Importante hacer esto solo con bases de datos de prueba, ya que si lo hacéis en producción eliminaréis las tablas y toda su información y la liaréis muy parda.

Login con JWT

Una vez realizado estos pasos, ya podremos loguearnos en nuestra API para generar un token, así que lo primero que haremos será lanzar el server de pruebas de Laravel:

php artisan serve

Una vez hecho esto, podéis guardar el email de cualquiera de los usuarios que hemos generado y utilizar una herramienta para realizar la prueba, en mi caso, voy a utilizar Postman. La url a la que debemos apuntar será http://localhost:8000/api/v1/auth/login y haremos una petición de tipo POST en la que enviaremos el email y el password (todos los usuarios generados tienen el mismo password que valga la redundancia es "password") en formato json.

Si todo ha ido bien, deberíais poder ver algo como esto:

Y listo, esto es todo lo que necesitáis para poder realizar login con JWT en Laravel 8. Recordad que tendrá una hora de validez y para utilizar el token, deberéis añadirlo en la cabecera de los endpoints que necesiten autenticación con el siguiente formato:

Authorization: Bearer <token>

Ahora que ya hemos aprendido a realizar el login mediante JWT, os invito a que veáis el siguiente tutorial en el que probaremos el funcionamiento de la autenticación y aprenderemos a crear un CRUD desde 0 💪.

Como siempre os dejo el enlace al proyecto y os recomiendo seguirme en Twitter para estar al tanto de los nuevos tutoriales.

Nos leemos 👋.

5097 vistas

🐍 Sígueme en Twitter

Si te gusta el contenido que subo y no quieres perderte nada, sígueme en Twitter y te avisaré cada vez que cree contenido nuevo 💪
Luego ¡Te sigo!

Nos tomamos en serio tu privacidad

Utilizamos cookies propias y de terceros para mejorar la experiencia del usuario a través de su navegación. Si pulsas entendido aceptas su uso. Ver política de cookies.