11: Conoce y usa Laravel Jetstream

 

11: Conoce y usa Laravel Jetstream

Introducción

En este tutorial exploraremos Laravel Jetstream, una herramienta poderosa que hemos instalado en nuestro proyecto y que nos proporciona un sistema completo de autenticación, gestión de perfiles y una base sólida para construir aplicaciones modernas. Aprenderemos cómo funciona, qué componentes genera y cómo podemos empezar a personalizarlos.


¿Qué es Laravel Jetstream?

Laravel Jetstream es un paquete oficial de Laravel que proporciona un scaffolding de autenticación moderno y completo. Incluye:

  • Registro e inicio de sesión de usuarios

  • Verificación de email

  • Restablecimiento de contraseña

  • Autenticación de dos factores (2FA)

  • Gestión de sesiones del navegador

  • Gestión de perfiles con foto de perfil

  • Gestión de equipos (opcional)

  • Tokens API (opcional)

Jetstream soporta dos stacks principales:

  • Livewire: Para aplicaciones con interacción en el backend

  • Inertia.js: Para aplicaciones SPA con Vue.js o React

Nosotros utilizaremos Inertia con Vue.js, que es el stack que elegimos en el tutorial anterior.


Paso 1: Instalar Jetstream (si no lo has hecho)

Si aún no tienes Jetstream instalado, ejecuta:

bash
composer require laravel/jetstream

Luego, instálalo con el stack Inertia:

bash
php artisan jetstream:install inertia

Instala las dependencias NPM y compila:

bash
npm install
npm run build

Paso 2: Ejecutar las migraciones

Jetstream añade nuevas tablas necesarias para la autenticación y gestión de usuarios:

bash
php artisan migrate

Las tablas que Jetstream crea incluyen:

  • users - Tabla de usuarios

  • password_reset_tokens - Tokens para restablecimiento de contraseña

  • sessions - Sesiones de usuario

  • personal_access_tokens - Tokens de API (Laravel Sanctum)

  • failed_jobs - Registro de trabajos fallidos


Paso 3: Explorar la estructura generada

Jetstream genera una gran cantidad de archivos y componentes. Vamos a revisar los más importantes:

3.1 Estructura de Backend

text
app/
├── Actions/
│   ├── Fortify/
│   │   ├── CreateNewUser.php      # Lógica para crear usuarios
│   │   ├── UpdateUserPassword.php # Actualizar contraseña
│   │   ├── UpdateUserProfileInformation.php # Actualizar perfil
│   │   └── ...
│   └── Jetstream/
│       ├── AddTeamMember.php      # Agregar miembros a equipos
│       ├── CreateTeam.php         # Crear equipos
│       ├── DeleteTeam.php         # Eliminar equipos
│       └── ...
├── Http/
│   ├── Controllers/
│   │   └── ProfileController.php  # Gestión del perfil
│   ├── Middleware/
│   │   └── ...
│   └── ...

3.2 Estructura de Frontend

text
resources/
├── js/
│   ├── Components/
│   │   ├── ApplicationLogo.vue    # Logo de la aplicación
│   │   ├── AuthenticationCard.vue # Tarjeta de autenticación
│   │   ├── Button.vue              # Botón reutilizable
│   │   ├── Input.vue               # Campo de entrada
│   │   ├── InputError.vue          # Mensaje de error
│   │   ├── Label.vue               # Etiqueta de formulario
│   │   ├── Modal.vue               # Ventana modal
│   │   ├── NavLink.vue             # Enlace de navegación
│   │   └── ...
│   ├── Layouts/
│   │   └── AppLayout.vue          # Layout principal
│   ├── Pages/
│   │   ├── Dashboard.vue          # Página del dashboard
│   │   ├── Profile/
│   │   │   ├── Show.vue           # Ver perfil
│   │   │   ├── Partials/
│   │   │   │   ├── UpdateProfileInformationForm.vue
│   │   │   │   ├── UpdatePasswordForm.vue
│   │   │   │   ├── TwoFactorAuthenticationForm.vue
│   │   │   │   └── LogoutOtherBrowserSessionsForm.vue
│   │   ├── Auth/
│   │   │   ├── Login.vue          # Página de login
│   │   │   ├── Register.vue       # Página de registro
│   │   │   ├── ForgotPassword.vue # Recuperar contraseña
│   │   │   ├── ResetPassword.vue  # Restablecer contraseña
│   │   │   ├── VerifyEmail.vue    # Verificar email
│   │   │   └── TwoFactorChallenge.vue # Desafío 2FA
│   │   └── Welcome.vue            # Página de bienvenida
│   └── app.js                     # Punto de entrada de la aplicación

Paso 4: Configuración del archivo .env

Jetstream utiliza algunas variables de entorno adicionales. Asegúrate de tener estas configuraciones en tu .env:

env
# Configuración de la aplicación
APP_NAME="Mi Portafolio"
APP_URL=http://localhost:8000

# Configuración de base de datos
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=portfolio_cpa
DB_USERNAME=root
DB_PASSWORD=

# Configuración de Jetstream
JETSTREAM_STACK=inertia
JETSTREAM_FEATURES=profile,api,teams

Paso 5: Comprender las rutas

Jetstream configura automáticamente las rutas de autenticación. Revisa routes/web.php:

php
<?php

use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;

// Ruta de bienvenida
Route::get('/', function () {
    return inertia('Welcome');
})->name('home');

// Rutas de autenticación (manejadas por Fortify)
// No es necesario definirlas manualmente

// Dashboard (protegido)
Route::middleware(['auth:sanctum', 'verified'])->group(function () {
    Route::get('/dashboard', function () {
        return inertia('Dashboard');
    })->name('dashboard');
});

// Perfil de usuario (protegido)
Route::group(['middleware' => 'auth'], function () {
    Route::get('/user/profile', [ProfileController::class, 'show'])
        ->name('profile.show');
});

Paso 6: Probar el sistema de autenticación

6.1 Registrar un usuario

  1. Visita http://localhost:8000

  2. Haz clic en Register

  3. Completa el formulario con:

    • Name: Tu nombre

    • Email: test@example.com

    • Password: contraseña segura (mínimo 8 caracteres)

    • Confirm Password: confirmar contraseña

  4. Haz clic en Register

6.2 Iniciar sesión

  1. Ve a la página de login

  2. Ingresa tus credenciales

  3. Serás redirigido al Dashboard

6.3 Explorar el perfil

Una vez autenticado, ve a Profile en el menú de usuario. Aquí podrás:

  • Actualizar información de perfil: Nombre, email, foto

  • Cambiar contraseña

  • Configurar autenticación de dos factores

  • Gestionar sesiones activas


Paso 7: Personalizar la página de bienvenida

La página de bienvenida (resources/js/Pages/Welcome.vue) es donde comienza tu aplicación. Vamos a simplificarla y personalizarla:

vue
<template>
    <div class="min-h-screen bg-gray-100">
        <nav class="bg-white border-b border-gray-100">
            <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
                <div class="flex justify-between h-16">
                    <!-- Logo -->
                    <div class="flex items-center">
                        <ApplicationLogo class="w-8 h-8" />
                        <span class="ml-2 text-xl font-semibold">Mi Portafolio</span>
                    </div>

                    <!-- Enlaces de autenticación -->
                    <div class="flex items-center space-x-4">
                        <Link v-if="!$page.props.auth.user" :href="route('login')" class="text-gray-700 hover:text-gray-900">
                            Iniciar Sesión
                        </Link>
                        <Link v-if="!$page.props.auth.user" :href="route('register')" class="px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">
                            Registrarse
                        </Link>
                        <div v-else class="flex items-center space-x-3">
                            <Link :href="route('dashboard')" class="text-gray-700 hover:text-gray-900">
                                Dashboard
                            </Link>
                            <Link :href="route('profile.show')" class="text-gray-700 hover:text-gray-900">
                                Perfil
                            </Link>
                            <button @click="logout" class="text-gray-700 hover:text-gray-900">
                                Cerrar Sesión
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        </nav>

        <div class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-8">
                    <h1 class="text-4xl font-bold text-gray-900">
                        ¡Bienvenido a Mi Portafolio!
                    </h1>
                    <p class="mt-4 text-lg text-gray-600">
                        Este es el inicio de tu portafolio profesional con Laravel Jetstream e Inertia.js.
                    </p>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import { Link } from '@inertiajs/vue3';
import { router } from '@inertiajs/vue3';
import ApplicationLogo from '@/Components/ApplicationLogo.vue';

const logout = () => {
    router.post(route('logout'));
};
</script>

Paso 8: Entender el flujo de autenticación

8.1 Registro de usuario

  1. El usuario envía el formulario de registro

  2. CreateNewUser action valida y crea el usuario

  3. Laravel Fortify maneja la autenticación

  4. El usuario es redirigido al dashboard

8.2 Inicio de sesión

  1. El usuario envía credenciales

  2. Fortify valida las credenciales

  3. Se crea la sesión

  4. El usuario es redirigido al dashboard

8.3 Protección de rutas

Las rutas que requieren autenticación usan el middleware auth:

php
Route::middleware(['auth:sanctum', 'verified'])->group(function () {
    Route::get('/dashboard', function () {
        return inertia('Dashboard');
    })->name('dashboard');
});

Paso 9: Agregar funcionalidad de verificación de email

Para habilitar la verificación de email, asegúrate de que estas configuraciones estén activas:

env
# En .env
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=tu_usuario
MAIL_PASSWORD=tu_contraseña
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=hello@example.com
MAIL_FROM_NAME="${APP_NAME}"

En el modelo User, implementa MustVerifyEmail:

php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Sanctum\HasApiTokens;
use Laravel\Jetstream\HasProfilePhoto;

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens, HasProfilePhoto;
    // ...
}

Paso 10: Personalizar componentes de Jetstream

Jetstream te permite personalizar cada uno de sus componentes. Algunas personalizaciones comunes:

10.1 Cambiar colores

Modifica el archivo tailwind.config.js:

javascript
export default {
    theme: {
        extend: {
            colors: {
                primary: '#4F46E5', // Tu color personalizado
                secondary: '#7C3AED',
            },
        },
    },
}

10.2 Modificar el layout

Edita resources/js/Layouts/AppLayout.vue para cambiar la estructura de la aplicación:

vue
<template>
    <div class="min-h-screen bg-gray-100">
        <header class="bg-white shadow">
            <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
                <h1 class="text-3xl font-bold text-gray-900">
                    <slot name="header" />
                </h1>
            </div>
        </header>

        <main class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <slot />
            </div>
        </main>
    </div>
</template>

10.3 Agregar nuevos campos al registro

Modifica app/Actions/Fortify/CreateNewUser.php para agregar campos adicionales:

php
public function create(array $input)
{
    Validator::make($input, [
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'password' => ['required', 'string', 'min:8', 'confirmed'],
        'phone' => ['required', 'string', 'max:20'], // Nuevo campo
    ])->validate();

    return User::create([
        'name' => $input['name'],
        'email' => $input['email'],
        'password' => Hash::make($input['password']),
        'phone' => $input['phone'], // Nuevo campo
    ]);
}

Solución de problemas comunes

Error: "The manifest.json does not exist"

Solución: Compila los assets:

bash
npm run build

Error: "Unable to locate a class or view"

Solución: Verifica que las rutas y los nombres de las vistas coincidan.

Error: "419 Page Expired"

Solución: Asegúrate de que el token CSRF esté incluido en las peticiones:

vue
<template>
    <form @submit.prevent="submit">
        <!-- El token CSRF se maneja automáticamente con Inertia -->
    </form>
</template>

Problema con las dependencias npm

Si encuentras errores con dependencias legacy:

bash
npm install --legacy-peer-deps
npm run dev

Resumen

✅ Exploramos la estructura generada por Laravel Jetstream
✅ Aprendimos a usar el sistema de autenticación
✅ Personalizamos la página de bienvenida
✅ Entendimos el flujo de autenticación
✅ Modificamos componentes y agregamos nuevos campos

¡Excelente trabajo! Ahora tienes un conocimiento sólido de cómo funciona Laravel Jetstream y cómo puedes personalizarlo para tu portafolio. Con esta base, puedes comenzar a construir las funcionalidades específicas de tu aplicación.


Recursos adicionales


¿Tienes preguntas sobre Jetstream? Recuerda que la documentación oficial y los videos del curso pueden ayudarte a resolver cualquier duda

Comentarios

Entradas más populares de este blog

Tareas con Laravel + Inertia + Jetstream

HACER CAMBIOS-AL EJEMPLO POR DEFECTO

Laravel + Inertia - ejemplo