Laravel

Laravel

Tutorial Laravel: Seguridad Autenticación y autorización

Laravel Autenticación: Aprende a usar Breeze y Jetstream para gestionar usuarios y perfiles. Fortalece la seguridad de tus aplicaciones fácilmente.

Aprende Laravel GRATIS y certifícate

Autenticación con Laravel Breeze y Jetstream

Laravel ofrece soluciones eficientes para implementar autenticación en nuestras aplicaciones mediante los paquetes Laravel Breeze y Laravel Jetstream. Ambos proporcionan una base sólida para gestionar usuarios, pero difieren en complejidad y funcionalidades.

Laravel Breeze es un kit de inicio minimalista que incluye la implementación básica de registro, inicio de sesión, restablecimiento de contraseñas y verificación de correo electrónico. Utiliza Blade Templates y Tailwind CSS, lo que facilita su personalización y adaptación a las necesidades del proyecto.

Para instalar Laravel Breeze en una nueva aplicación, ejecuta:

composer require laravel/breeze --dev

Luego, ejecuta el instalador para generar las rutas, controladores y vistas necesarios:

php artisan breeze:install

Después de la instalación, migra las tablas de la base de datos con:

php artisan migrate

Inicia el servidor web integrado de PHP:

php -S localhost:8000 -t public

Ahora, al acceder a http://localhost:8000, tendrás una interfaz de autenticación funcional y lista para usar.

Por otro lado, Laravel Jetstream es un paquete más avanzado que extiende las funcionalidades de Breeze. Incluye características como gestión de perfiles, autenticación de dos factores, gestión de sesiones y soporte para equipos. Jetstream es ideal para aplicaciones que requieren una experiencia de usuario más completa y dinámica.

Para instalar Laravel Jetstream, primero agrega el paquete:

composer require laravel/jetstream

A continuación, elige el stack que prefieras: Livewire o Inertia.js. Por ejemplo, para instalar con Livewire:

php artisan jetstream:install livewire

O con Inertia.js:

php artisan jetstream:install inertia

Después de la instalación, ejecuta las migraciones y compila los activos front-end:

php artisan migrate
npm install
npm run dev

Inicia el servidor:

php -S localhost:8000 -t public

Con Jetstream, tendrás acceso a componentes prediseñados que utilizan Livewire o Inertia.js, ofreciendo una interfaz más interactiva y reactiva.

Es importante resaltar que tanto Breeze como Jetstream están diseñados para ser personalizables. Puedes modificar las vistas, rutas y lógica según los requerimientos específicos de tu aplicación.

La elección entre Breeze y Jetstream depende de las necesidades del proyecto. Si buscas una solución sencilla y ligera, Breeze es adecuado. Si necesitas funcionalidades más avanzadas y una interfaz de usuario enriquecida, Jetstream es la opción recomendada.

Ambos paquetes siguen las mejores prácticas de desarrollo en Laravel y están mantenidos por la comunidad, garantizando seguridad y actualizaciones constantes.

Al utilizar estas herramientas, ahorras tiempo en la implementación de sistemas de autenticación, permitiéndote centrarte en desarrollar las funcionalidades clave de tu aplicación.

Registro, inicio de sesión y restablecimiento de contraseñas

Laravel proporciona una infraestructura completa para manejar el registro, inicio de sesión y restablecimiento de contraseñas de usuarios en tu aplicación. Estas funcionalidades están integradas en Laravel Breeze y Jetstream, lo que permite implementarlas de forma rápida y segura.

Registro de usuarios

El proceso de registro permite a los nuevos usuarios crear una cuenta. Laravel ofrece una ruta predeterminada /register y una vista asociada que puedes encontrar en resources/views/auth/register.blade.php. Este formulario incluye campos para el nombre, correo electrónico y contraseña.

Ejemplo de formulario de registro:

<form method="POST" action="{{ route('register') }}">
    @csrf
    <input type="text" name="name" required autofocus>
    <input type="email" name="email" required>
    <input type="password" name="password" required autocomplete="new-password">
    <input type="password" name="password_confirmation" required>
    <button type="submit">Registrarse</button>
</form>

En el controlador de registro, se validan los datos y se crea el usuario:

public function store(Request $request)
{
    $request->validate([
        'name' => 'required|string|max:255',
        'email' => 'required|string|email|max:255|unique:users',
        'password' => 'required|string|confirmed|min:8',
    ]);

    $user = User::create([
        'name' => $request->name,
        'email' => $request->email,
        'password' => Hash::make($request->password),
    ]);

    Auth::login($user);

    return redirect()->route('dashboard');
}

Observa que la contraseña se encripta utilizando Hash::make() antes de almacenarla en la base de datos.

Inicio de sesión

Para el inicio de sesión, Laravel proporciona la ruta /login y su vista correspondiente en resources/views/auth/login.blade.php. El formulario solicita el correo electrónico y la contraseña del usuario.

Ejemplo de formulario de inicio de sesión:

<form method="POST" action="{{ route('login') }}">
    @csrf
    <input type="email" name="email" required autofocus>
    <input type="password" name="password" required autocomplete="current-password">
    <button type="submit">Iniciar sesión</button>
</form>

El controlador de autenticación verifica las credenciales:

public function store(Request $request)
{
    $credentials = $request->validate([
        'email' => ['required', 'string', 'email'],
        'password' => ['required', 'string'],
    ]);

    if (Auth::attempt($credentials)) {
        $request->session()->regenerate();
        return redirect()->intended('dashboard');
    }

    return back()->withErrors([
        'email' => 'Las credenciales proporcionadas no coinciden con nuestros registros.',
    ]);
}

La regeneración de la sesión después de un inicio de sesión exitoso es esencial para proteger contra ataques de fijación de sesión.

Restablecimiento de contraseñas

Cuando un usuario olvida su contraseña, Laravel facilita su restablecimiento mediante un proceso seguro:

  1. Solicitud de restablecimiento: El usuario accede a /forgot-password y envía su correo electrónico.
  2. Envío de correo: Laravel envía un correo electrónico con un enlace de restablecimiento que incluye un token único.
  3. Formulario de nueva contraseña: Al seguir el enlace, el usuario llega a /reset-password/{token} donde puede ingresar una nueva contraseña.
  4. Actualización de contraseña: Al enviar el formulario, se valida el token y se actualiza la contraseña en la base de datos.

Configura los detalles de tu servidor de correo en el archivo .env:

MAIL_MAILER=smtp
MAIL_HOST=smtp.tu-servidor.com
MAIL_PORT=587
MAIL_USERNAME=tu_usuario
MAIL_PASSWORD=tu_contraseña
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=no-reply@tu-dominio.com
MAIL_FROM_NAME="Tu Aplicación"

Asegúrate de que tu aplicación pueda enviar correos electrónicos correctamente para que este proceso funcione.

Personalización de las vistas de autenticación

Las vistas predeterminadas se pueden modificar para adaptarse al diseño de tu aplicación. Ubicadas en resources/views/auth, puedes ajustar los formularios y mensajes según tus necesidades. Por ejemplo, para añadir un campo de número de teléfono al formulario de registro:

  1. Añade el campo en register.blade.php:
   <input type="text" name="phone" required>
  1. Actualiza la validación en el controlador:
   $request->validate([
       // ...
       'phone' => 'required|string|max:15',
   ]);
  1. Añade el campo al modelo User en $fillable:
   protected $fillable = [
       'name',
       'email',
       'password',
       'phone',
   ];

Protección de rutas con middleware

Para restringir el acceso a ciertas rutas solo a usuarios autenticados, utiliza el middleware auth. Al definir tus rutas en routes/web.php:

Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware('auth')
    ->name('dashboard');

Esto garantiza que solo los usuarios con una sesión activa puedan acceder al dashboard u otras secciones protegidas.

Cierre de sesión

Proporciona una opción para que los usuarios puedan cerrar sesión de forma segura. La ruta /logout y su método asociado en el controlador gestionan este proceso:

public function destroy(Request $request)
{
    Auth::logout();

    $request->session()->invalidate();
    $request->session()->regenerateToken();

    return redirect('/');
}

La invalidación de la sesión y la regeneración del token CSRF son cruciales para mantener la seguridad.

Mejores prácticas de seguridad

  • Validación exhaustiva: Siempre valida los datos proporcionados por el usuario para proteger contra inyecciones y otros ataques.
  • Encriptación de contraseñas: Utiliza funciones de hashing seguras, como bcrypt, para almacenar contraseñas.
  • Uso de HTTPS: Implementa SSL/TLS en tu servidor para cifrar la comunicación y proteger la información sensible.
  • Protección contra CSRF: Laravel incluye automáticamente tokens CSRF en formularios para prevenir solicitudes maliciosas.
  • Actualizaciones regulares: Mantén tu instalación de Laravel y sus dependencias actualizadas para beneficiarte de los últimos parches de seguridad.

Al seguir estos pasos y aprovechar las herramientas que Laravel ofrece, puedes implementar un sistema de autenticación robusto que mejore la experiencia del usuario y garantice la seguridad de tu aplicación.

Middleware de autenticación

El middleware de autenticación en Laravel es una herramienta esencial para controlar el acceso a las rutas y recursos de tu aplicación. Actúa como una capa intermedia que verifica si un usuario está autenticado antes de permitirle interactuar con determinadas partes del sistema, mejorando así la seguridad de tu aplicación.

Para aplicar el middleware de autenticación a una ruta específica, puedes utilizar el método middleware en la definición de la ruta dentro del archivo routes/web.php:

Route::get('/perfil', [PerfilController::class, 'mostrar'])
    ->middleware('auth')
    ->name('perfil.mostrar');

En este ejemplo, la ruta /perfil está protegida por el middleware 'auth'. Esto significa que solo los usuarios autenticados podrán acceder a ella. Si un usuario no autenticado intenta acceder, será redirigido a la página de inicio de sesión.

También es posible aplicar el middleware de autenticación a un grupo de rutas, lo cual es útil cuando deseas proteger múltiples rutas bajo la misma condición:

Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
    Route::get('/configuracion', [ConfiguracionController::class, 'index'])->name('configuracion');
    // Otras rutas protegidas
});

De esta manera, todas las rutas dentro del grupo solo serán accesibles para usuarios que hayan iniciado sesión.

Aplicación de middleware en controladores

Otra forma de utilizar el middleware es directamente en los controladores. Al definir el middleware en el constructor del controlador, aseguras que todas las acciones dentro de ese controlador requieran autenticación:

class PerfilController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    // Métodos del controlador
}

Esto simplifica la protección de rutas, especialmente cuando el controlador maneja exclusivamente funcionalidades que requieren que el usuario esté autenticado.

Middleware de invitado

Laravel también proporciona el middleware 'guest', que es lo opuesto a 'auth'. Este middleware verifica que el usuario no esté autenticado. Es útil para rutas como el formulario de registro o de inicio de sesión, donde no tiene sentido permitir el acceso a usuarios ya autenticados:

Route::get('/login', [AuthController::class, 'mostrarFormularioLogin'])
    ->middleware('guest')
    ->name('login');

Con esta configuración, un usuario autenticado que intente acceder a /login será redireccionado, evitando accesos innecesarios.

Redirecciones personalizadas

El middleware de autenticación por defecto redirige a la ruta 'login' cuando un usuario no autenticado intenta acceder a una ruta protegida. Si deseas cambiar esta ruta o personalizar el comportamiento, puedes modificar el método redirectTo en el archivo app/Http/Middleware/Authenticate.php:

protected function redirectTo($request)
{
    if (! $request->expectsJson()) {
        return route('acceso.denegado');
    }
}

Esto permite dirigir al usuario a una página específica, como una vista personalizada que informe que el acceso está restringido.

Middleware de autenticación para APIs

Cuando trabajas con APIs, es común utilizar tokens para la autenticación. Laravel proporciona el middleware 'auth:api', que puedes aplicar a tus rutas de API definidas en routes/api.php:

Route::middleware('auth:api')->get('/usuario', function (Request $request) {
    return $request->user();
});

Este middleware verifica que la solicitud incluya un token válido antes de permitir el acceso a la ruta.

Creación de middleware personalizado

Si necesitas una lógica de autenticación más específica, puedes crear un middleware personalizado. Por ejemplo, para verificar si el usuario tiene un rol particular:

  1. Genera el middleware usando Artisan:
php artisan make:middleware VerificarRol
  1. En el archivo app/Http/Middleware/VerificarRol.php, implementa la lógica deseada:
public function handle($request, Closure $next, $rol)
{
    if (! $request->user() || ! $request->user()->tieneRol($rol)) {
        return redirect('/acceso-denegado');
    }

    return $next($request);
}
  1. Registra el middleware en app/Http/Kernel.php:
protected $routeMiddleware = [
    // Otros middlewares
    'verificar.rol' => \App\Http\Middleware\VerificarRol::class,
];
  1. Aplica el middleware a las rutas, pasando los parámetros necesarios:
Route::get('/admin', [AdminController::class, 'index'])
->middleware('verificar.rol:administrador')
->name('admin.index');

Combinación de middlewares

Es posible aplicar múltiples middlewares a una misma ruta o grupo de rutas para cubrir diversas condiciones de acceso:

Route::middleware(['auth', 'verificar.rol:editor'])->group(function () {
    Route::get('/editar', [EditorController::class, 'editar'])->name('contenido.editar');
    // Otras rutas para editores
});

Aquí, el acceso está limitado a usuarios autenticados que además tengan el rol de editor, proporcionando un control de acceso más granular.

Middleware y guardias de autenticación

Laravel utiliza el concepto de guardias (guards) para manejar diferentes formas de autenticación. Por defecto, el middleware 'auth' utiliza el guardia 'web', pero puedes especificar otro guardia según tus necesidades:

Route::middleware('auth:admin')->group(function () {
    // Rutas protegidas bajo el guardia 'admin'
});

Debes configurar los guardias adicionales en el archivo config/auth.php, donde defines cómo se autenticará cada tipo de usuario.

Protección contra ataques CSRF

Aunque no es un middleware de autenticación, el middleware 'VerifyCsrfToken' es crucial para la seguridad de tu aplicación, ya que protege contra ataques de falsificación de solicitudes en sitios cruzados. Laravel incluye este middleware de forma predeterminada en las rutas web:

protected $middlewareGroups = [
    'web' => [
        // Otros middlewares
        \App\Http\Middleware\VerifyCsrfToken::class,
    ],
];

Asegúrate de mantener este middleware activo para todas las rutas que aceptan solicitudes POST, PUT, PATCH o DELETE.

Consideraciones adicionales

  • Excepciones en middleware: Puedes excluir ciertas rutas del middleware de autenticación si es necesario, aunque se recomienda hacerlo con precaución.
  • Middleware globales: Algunos middlewares se aplican a todas las solicitudes de la aplicación. Estos se definen en la propiedad $middleware del Kernel.
  • Orden de los middlewares: El orden en que se aplican los middlewares puede ser importante, especialmente si un middleware depende de otro. Laravel los ejecuta en el orden en que aparecen en el arreglo de middlewares.

Al aprovechar el middleware de autenticación, puedes controlar de forma efectiva quién accede a qué en tu aplicación, asegurando que solo los usuarios adecuados interactúen con las funcionalidades correspondientes. Esto es fundamental para mantener la integridad y confiabilidad del sistema.

Autorización con Gates y Policies

La autorización en Laravel es el proceso que determina si un usuario autenticado tiene permiso para realizar una acción específica. Laravel proporciona dos mecanismos principales para gestionar la autorización: Gates y Policies. Ambas herramientas permiten controlar el acceso a recursos de forma granular, mejorando la seguridad y la organización del código.

Gates (puertas) son cierres (Closure) sencillos que determinan si un usuario puede realizar una acción determinada. Por otro lado, las Policies (políticas) son clases que agrupan la lógica de autorización alrededor de un modelo o recurso específico. Elegir entre Gates y Policies depende de la complejidad y el alcance de las reglas de autorización que necesites implementar.

Implementación de Gates

Las Gates son ideales para definiciones de autorización simples y globales. Se definen en el método boot del AuthServiceProvider, ubicado en app/Providers/AuthServiceProvider.php.

Ejemplo de una Gate que verifica si un usuario es administrador:

use Illuminate\Support\Facades\Gate;

public function boot()
{
    $this->registerPolicies();

    Gate::define('acceder-panel-administracion', function ($user) {
        return $user->esAdministrador();
    });
}

En este ejemplo, la Gate 'acceder-panel-administracion' comprueba si el método esAdministrador() del usuario autenticado devuelve true. Puedes utilizar esta Gate en tus controladores o vistas Blade para restringir el acceso.

Para verificar una Gate en un controlador:

public function index()
{
    if (Gate::allows('acceder-panel-administracion')) {
        // El usuario puede acceder al panel de administración
    } else {
        // Acceso denegado
        abort(403);
    }
}

En vistas Blade, puedes utilizar las directivas @can y @cannot:

@can('acceder-panel-administracion')
    <a href="{{ route('admin.dashboard') }}">Panel de Administración</a>
@endcan

Implementación de Policies

Las Policies se utilizan para agrupar las reglas de autorización relacionadas con un modelo o recurso. Esto es útil para mantener el código organizado y manejable en aplicaciones más complejas.

Para crear una Policy, utiliza el comando Artisan:

php artisan make:policy PostPolicy --model=Post

Este comando genera una clase PostPolicy en app/Policies, asociada al modelo Post. En esta clase, puedes definir métodos que determinen si el usuario puede realizar ciertas acciones sobre instancias de Post.

Ejemplo de una Policy para el modelo Post:

class PostPolicy
{
    public function update(User $user, Post $post)
    {
        return $user->id === $post->autor_id;
    }

    public function delete(User $user, Post $post)
    {
        return $user->id === $post->autor_id;
    }
}

En este caso, el usuario puede actualizar o eliminar un Post si es el autor del mismo.

No olvides registrar la Policy en el AuthServiceProvider:

protected $policies = [
    Post::class => PostPolicy::class,
];

Para utilizar las Policies en un controlador, utiliza el método authorize o las facades Gate y Policy:

public function update(Request $request, Post $post)
{
    $this->authorize('update', $post);

    // Lógica para actualizar el post
}

Si el usuario no está autorizado, se lanzará una excepción AuthorizationException, resultando en una respuesta 403.

En vistas Blade, puedes aplicar las directivas @can y @cannot pasando el modelo como segundo parámetro:

@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}">Editar</a>
@endcan

Autorización basada en recursos

Laravel ofrece una forma abreviada de aplicar Policies a controladores mediante el uso de authorizeResource. En el constructor del controlador, puedes indicar:

public function __construct()
{
    $this->authorizeResource(Post::class, 'post');
}

Esto aplica automáticamente la autorización correspondiente a los métodos del controlador RESTful basado en el modelo Post.

Definiendo métodos de autorización

Las Policies pueden incluir métodos para acciones personalizadas. Por ejemplo, si tienes una acción para publicar un Post:

class PostPolicy
{
    public function publicar(User $user, Post $post)
    {
        return $user->esEditor() || $user->id === $post->autor_id;
    }
}

Luego, en el controlador:

public function publicar(Post $post)
{
    $this->authorize('publicar', $post);

    // Lógica para publicar el post
}

Autorización previa al modelo

A veces, necesitas autorizar acciones que no están relacionadas con una instancia específica del modelo. Puedes definir métodos en la Policy que solo reciben el objeto User:

class PostPolicy
{
    public function crear(User $user)
    {
        return $user->tienePermiso('crear-post');
    }
}

En el controlador:

public function create()
{
    $this->authorize('crear', Post::class);

    // Lógica para mostrar el formulario de creación
}

Negando automáticamente acciones

Puedes definir un método before en la Policy que se ejecuta antes de cualquier otro método de autorización. Esto es útil para conceder o denegar acceso globalmente:

public function before(User $user, $ability)
{
    if ($user->esAdministrador()) {
        return true;
    }
}

En este caso, si el usuario es administrador, se le concederá acceso a todas las acciones relacionadas con la Policy.

Combinación de Gates y Policies

Aunque las Policies son ideales para modelos específicos, las Gates son útiles para autorizaciones globales o acciones que no están ligadas a un modelo. Puedes combinar ambos métodos según las necesidades de tu aplicación.

Uso de middleware para autorización

Además de verificar autorizaciones en controladores y vistas, puedes aplicar restricciones mediante middleware. Laravel proporciona el middleware can, que puedes utilizar en tus rutas:

Route::delete('/posts/{post}', [PostController::class, 'destroy'])
    ->middleware('can:delete,post')
    ->name('posts.destroy');

Este middleware verifica la Policy delete para el modelo Post antes de permitir el acceso a la ruta.

Autorización y control de acceso en Blade

Las directivas Blade adicionales @canany y @elsecan permiten mayor flexibilidad en las vistas:

@canany(['update', 'delete'], $post)
    <!-- El usuario puede actualizar o eliminar el post -->
@endcanany

Estas directivas mejoran la experiencia del usuario al mostrar u ocultar elementos de la interfaz según sus permisos.

Mejores prácticas en autorización

  • Organización del código: Utiliza Policies para mantener las reglas de autorización ordenadas y manejables.
  • Reutilización: Define métodos comunes en las Policies para evitar duplicación de código.
  • Seguridad: Siempre verifica las autorizaciones incluso si no se muestran opciones en la interfaz, para prevenir accesos no autorizados por métodos alternativos.
  • Consistencia: Aplica las mismas reglas de autorización tanto en controladores como en vistas para asegurar un comportamiento coherente.

Al implementar Gates y Policies correctamente, puedes controlar de manera efectiva quién puede realizar ciertas acciones en tu aplicación, fortaleciendo la seguridad y garantizando que los usuarios solo accedan a las funcionalidades a las que están autorizados.

Para seguir leyendo hazte Plus

¿Ya eres Plus? Accede a la app

Plan mensual

19.00 € /mes

Precio normal mensual: 19 €
47 % DE DESCUENTO

Plan anual

10.00 € /mes

Ahorras 108 € al año
Precio normal anual: 120 €
Aprende Laravel GRATIS online

Todas las lecciones de Laravel

Accede a todas las lecciones de Laravel y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a Laravel y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Implementar autenticación básica con Laravel Breeze.
  • Configurar autenticaciones avanzadas con Jetstream.
  • Personalizar vistas de autenticación usando Blade y Tailwind CSS.
  • Comprender la diferencia entre autenticación con Breeze y Jetstream.
  • Proteger rutas utilizando el middleware de autenticación.
  • Manejar el registro, inicio de sesión y restablecimiento de contraseñas de forma segura.