1. Conceptos básicos
  2. Sesión HTTP

Introducción

Dado que las aplicaciones impulsadas por HTTP son sin estado, las sesiones proporcionan una manera de almacenar información sobre el usuario en varias solicitudes. Esa información del usuario se coloca típicamente en una tienda / backend persistente que se puede acceder desde solicitudes posteriores.

Laravel incluye una variedad de backends de sesión a los que se accede a través de una API expresiva y unificada. Se incluye soporte para backends populares como Memcached, Redis y bases de datos.

Configuración

El archivo de configuración de sesión de su aplicación se encuentra en config/session.php. Asegúrese de revisar las opciones disponibles en este archivo. De forma predeterminada, Laravel está configurado para usar el controlador de sesión file, que funcionará bien para muchas aplicaciones. Si su aplicación se equilibrará entre varios servidores web, debe elegir una tienda centralizada a la que todos los servidores puedan acceder, como Redis o una base de datos.

La opción de configuración driver de la sesión define dónde se almacenarán los datos de la sesión para cada solicitud. Laravel incluye varios excelentes controladores de forma predeterminada:

  • file - las sesiones se almacenan en storage/framework/sessions.
  • cookie - las sesiones se almacenan en cookies seguras y cifradas.
  • database - las sesiones se almacenan en una base de datos relacional.
  • memcached / redis - las sesiones se almacenan en una de estas tiendas rápidas basadas en caché.
  • dynamodb - las sesiones se almacenan en AWS DynamoDB.
  • array - las sesiones se almacenan en una matriz de PHP y no se persistirán.

Nota El controlador de matriz se utiliza principalmente durante las pruebas y evita que los datos almacenados en la sesión se persistan.

Requisitos Previos del Controlador

Base de Datos

Cuando utilice el controlador de sesión database, deberá crear una tabla para contener los registros de sesión. Se puede encontrar un ejemplo de declaración de Schema para la tabla a continuación:

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity')->index();
});

Puede utilizar el comando Artisan session:table para generar esta migración. Para obtener más información sobre las migraciones de base de datos, puede consultar la documentación completa de migraciones:

php artisan session:table
 
php artisan migrate

Redis

Antes de utilizar sesiones Redis con Laravel, deberá instalar la extensión de PHP PhpRedis a través de PECL o instalar el paquete predis/predis (~1.0) a través de Composer. Para obtener más información sobre la configuración de Redis, consulte la documentación de Redis de Laravel.

Nota En el archivo de configuración session, la opción connection se puede usar para especificar qué conexión de Redis se utiliza para la sesión.

Interactuar con la Sesión

Recuperar Datos

Hay dos formas principales de trabajar con datos de sesión en Laravel: el ayudante global session y mediante una instancia de Request. Primero, veamos cómo acceder a la sesión a través de una instancia de Request, que puede ser tipo-hinted en un cierre de ruta o en un método del controlador. Recuerde, las dependencias del método del controlador se inyectan automáticamente a través del contenedor de servicios de Laravel:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use Illuminate\View\View;
 
class UserController extends Controller
{
/**
* Mostrar el perfil del usuario dado.
*/
public function show(Request $request, string $id): View
{
$value = $request->session()->get('key');
 
// ...
 
$user = $this->users->find($id);
 
return view('user.profile', ['user' => $user]);
}
}

Cuando recupera un elemento de la sesión, también puede pasar un valor predeterminado como segundo argumento al método get. Este valor predeterminado se devolverá si la clave especificada no existe en la sesión. Si pasa un cierre como valor predeterminado al método get y la clave solicitada no existe, se ejecutará el cierre y se devolverá su resultado:

$value = $request->session()->get('key', 'default');
 
$value = $request->session()->get('key', function () {
return 'default';
});

El Ayudante Global de Sesión

También puede utilizar la función global de PHP session para recuperar y almacenar datos en la sesión. Cuando se llama al ayudante session con un solo argumento de cadena, devolverá el valor de esa clave de sesión. Cuando el ayudante se llama con una matriz de pares clave/valor, esos valores se almacenarán en la sesión:

Route::get('/home', function () {
// Obtener un dato de la sesión...
$value = session('key');
 
// Especificar un valor predeterminado...
$value = session('key', 'default');
 
// Almacenar un dato en la sesión...
session(['key' => 'value']);
});

Nota Hay poca diferencia práctica entre usar la sesión a través de una instancia de solicitud HTTP y utilizar el ayudante global session. Ambos métodos son testables mediante el método assertSessionHas que está disponible en todos sus casos de prueba.

Recuperar Todos los Datos de Sesión

Si desea recuperar todos los datos de la sesión, puede utilizar el método all:

$data = $request->session()->all();

Determinar Si un Elemento Existe en la Sesión

Para determinar si un elemento está presente en la sesión, puede utilizar el método has. El método has devuelve true si el elemento está presente y no es null:

if ($request->session()->has('users')) {
// ...
}

Para determinar si un elemento está presente en la sesión, incluso si su valor es null, puede utilizar el método exists:

if ($request->session()->exists('users')) {
// ...
}

Para determinar si un elemento no está presente en la sesión, puede utilizar el método missing. El método missing devuelve true si el elemento no está presente:

if ($request->session()->missing('users')) {
// ...
}

Almacenar Datos

Para almacenar datos en la sesión, normalmente utilizará el método put de la instancia de solicitud o el ayudante global session:

// A través de una instancia de solicitud...
$request->session()->put('key', 'value');
 
// A través del ayudante global "session"...
session(['key' => 'value']);

Agregar Valores a un Array en Sesión

El método push se puede utilizar para agregar un nuevo valor a un valor de sesión que es una matriz. Por ejemplo, si la clave user.teams contiene una matriz de nombres de equipos, puede agregar un nuevo valor a la matriz de la siguiente manera:

$request->session()->push('user.teams', 'developers');

Recuperar y Eliminar un Elemento

El método pull recuperará y eliminará un elemento de la sesión en una sola declaración:

$value = $request->session()->pull('key', 'default');

Incrementar y Decrementar Valores de Sesión

Si los datos de su sesión contienen un número entero que desea incrementar o decrementar, puede utilizar los métodos increment y decrement:

$request->session()->increment('count');
 
$request->session()->increment('count', $incrementBy = 2);
 
$request->session()->decrement('count');
 
$request->session()->decrement('count', $decrementBy = 2);

Datos Flash

A veces puede desear almacenar elementos en la sesión para la próxima solicitud. Puede hacerlo utilizando el método flash. Los datos almacenados en la sesión utilizando este método estarán disponibles inmediatamente y durante la siguiente solicitud HTTP. Después de la siguiente solicitud HTTP, los datos destellados se eliminarán. Los datos de destello son principalmente útiles para mensajes de estado de corta duración:

$request->session()->flash('status', 'Task was successful!');

Si necesita persistir sus datos de destello durante varias solicitudes, puede utilizar el método reflash, que mantendrá todos los datos de destello durante una solicitud adicional. Si solo necesita mantener datos de destello específicos, puede utilizar el método keep:

$request->session()->reflash();
 
$request->session()->keep(['username', 'email']);

Para persistir sus datos de destello solo durante la solicitud actual, puede utilizar el método now:

$request->session()->now('status', 'Task was successful!');

Eliminar Datos

El método forget eliminará un dato de la sesión. Si desea eliminar todos los datos de la sesión, puede utilizar el método flush:

// Olvidar una clave única...
$request->session()->forget('name');
 
// Olvidar varias claves...
$request->session()->forget(['name', 'status']);
 
$request->session()->flush();

Regenerar el ID de Sesión

Regenerar el ID de sesión se hace a menudo para evitar que los usuarios malintencionados aprovechen un ataque de fijación de sesión en su aplicación.

Laravel regenera automáticamente el ID de sesión durante la autenticación si está utilizando uno de los kits de inicio de la aplicación Laravel o Laravel Fortify; sin embargo, si necesita regenerar manualmente el ID de sesión, puede utilizar el método regenerate:

$request->session()->regenerate();

Si necesita regenerar el ID de sesión y eliminar todos los datos de la sesión en una sola declaración, puede utilizar el método invalidate:

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

Bloqueo de Sesión

Advertencia Para utilizar el bloqueo de sesiones, su aplicación debe estar utilizando un controlador de caché que admita bloqueos atómicos. Actualmente, esos controladores de caché incluyen los controladores memcached, dynamodb, redis y database. Además, no puede utilizar el controlador de sesión cookie.

De forma predeterminada, Laravel permite que las solicitudes que utilizan la misma sesión se ejecuten de manera concurrente. Así que, por ejemplo, si utiliza una biblioteca HTTP de JavaScript para hacer dos solicitudes HTTP a su aplicación, ambas se ejecutarán al mismo tiempo. Para muchas aplicaciones, esto no es un problema; sin embargo, la pérdida de datos de sesión puede ocurrir en un pequeño conjunto de aplicaciones que realizan solicitudes concurrentes a dos puntos finales de la aplicación diferentes que escriben datos en la sesión.

Para mitigar esto, Laravel proporciona funcionalidad que le permite limitar las solicitudes concurrentes para una sesión dada. Para empezar, simplemente puede encadenar el método block en la definición de su ruta. En este ejemplo, una solicitud entrante al endpoint /profile adquiriría un bloqueo de sesión. Mientras se mantiene este bloqueo, cualquier solicitud entrante a los endpoints /profile o /order que compartan el mismo ID de sesión esperarán a que la primera solicitud termine de ejecutarse antes de continuar su ejecución:

Route::post('/profile', function () {
// ...
})->block($lockSeconds = 10, $waitSeconds = 10)
 
Route::post('/order', function () {
// ...
})->block($lockSeconds = 10, $waitSeconds = 10)

El método block acepta dos argumentos opcionales. El primer argumento aceptado por el método block es el tiempo máximo en segundos que se debe mantener el bloqueo de sesión antes de que se libere. Por supuesto, si la solicitud termina de ejecutarse antes de este tiempo, el bloqueo se liberará antes.

El segundo argumento aceptado por el método block es el tiempo máximo en segundos que una solicitud debe esperar al intentar obtener un bloqueo de sesión. Se lanzará una excepción Illuminate\Contracts\Cache\LockTimeoutException si la solicitud no puede obtener un bloqueo de sesión dentro del número dado de segundos.

Si no se pasa ninguno de estos argumentos, el bloqueo se obtendrá durante un máximo de 10 segundos y las solicitudes esperarán un máximo de 10 segundos al intentar obtener un bloqueo:

Route::post('/profile', function () {
// ...
})->block()

Agregar Controladores de Sesión Personalizados

Implementar el Controlador

Si ninguno de los controladores de sesión existentes satisface las necesidades de su aplicación, Laravel le permite escribir su propio controlador de sesión. Su controlador de sesión personalizado debe implementar SessionHandlerInterface incorporado en PHP. Esta interfaz contiene solo algunos métodos simples. Una implementación ficticia de MongoDB se ve así:

<?php
 
namespace App\Extensions;
 
class MongoSessionHandler implements \SessionHandlerInterface
{
public function open($savePath, $sessionName) {}
public function close() {}
public function read($sessionId) {}
public function write($sessionId, $data) {}
public function destroy($sessionId) {}
public function gc($lifetime) {}
}

Nota Laravel no incluye un directorio para contener sus extensiones. Puede colocarlas donde desee. En este ejemplo, hemos creado un directorio Extensions para alojar el MongoSessionHandler.

Dado que el propósito de estos métodos no es fácilmente comprensible, cubramos rápidamente qué hace cada uno de los métodos:

  • El método open se utilizaría típicamente en sistemas de almacenamiento de sesión basados en archivos. Dado que Laravel incluye un controlador de sesión file, rara vez necesitará poner algo en este método. Simplemente puede dejar este método vacío.
  • El método close, al igual que el método open, generalmente también se puede pasar por alto. Para la mayoría de los controladores, no es necesario.
  • El método read debe devolver la versión de cadena de los datos de la sesión asociados con el $sessionId dado. No es necesario realizar ninguna serialización u otro tipo de codificación al recuperar o almacenar datos de sesión en su controlador, ya que Laravel realizará la serialización por usted.
  • El método write debe escribir la cadena $data dada asociada con el $sessionId en algún sistema de almacenamiento persistente, como MongoDB u otro sistema de almacenamiento de su elección. Nuevamente, no debe realizar ninguna serialización, ya que Laravel ya habrá manejado eso por usted.
  • El método destroy debe eliminar los datos asociados con el $sessionId del almacenamiento persistente.
  • El método gc debe destruir todos los datos de sesión que sean más antiguos que el $lifetime dado, que es una marca de tiempo UNIX. Para sistemas de autodestrucción como Memcached y Redis, este método puede dejarse vacío.

Registrar el Controlador

Una vez que su controlador haya sido implementado, está listo para registrarlo con Laravel. Para agregar controladores adicionales al backend de sesión de Laravel, puede utilizar el método extend proporcionado por el facade Session. Debería llamar al método extend desde el método boot de un proveedor de servicios. Puede hacer esto desde el proveedor existente App\Providers\AppServiceProvider o crear un proveedor completamente nuevo:

<?php
 
namespace App\Providers;
 
use App\Extensions\MongoSessionHandler;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;
 
class SessionServiceProvider extends ServiceProvider
{
/**
* Registrar cualquier servicio de la aplicación.
*/
public function register(): void
{
// ...
}
 
/**
* Inicializar cualquier servicio de la aplicación.
*/
public function boot(): void
{
Session::extend('mongo', function (Application $app) {
// Devolver una implementación de SessionHandlerInterface...
return new MongoSessionHandler;
});
}
}

Una vez que se haya registrado el controlador de sesión, puede usar el controlador mongo en su archivo de configuración config/session.php.