Sesión HTTP
- Introducción
- Interacting With the Session
- Bloqueo de Sesión
- Agregar Controladores de Sesión Personalizados
Introducción
Dado que las aplicaciones impulsadas por HTTP son sin estado, las sesiones proporcionan una forma de almacenar información sobre el usuario a lo largo de múltiples solicitudes. Esa información del usuario se coloca típicamente en un almacenamiento / backend persistente que se puede acceder desde solicitudes posteriores. Laravel viene con una variedad de backends de sesión que se acceden a través de una API unificada y expresiva. Se incluye soporte para backends populares como Memcached, Redis y bases de datos.
Configuración
El archivo de configuración de sesión de tu aplicación se almacena en config/session.php
. Asegúrate de revisar las opciones disponibles en este archivo. Por defecto, Laravel está configurado para usar el driver de sesión database
.
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 una variedad de drivers:
-
file
- sessions are stored instorage/framework/sessions
. -
cookie
- sessions are stored in secure, encrypted cookies. -
database
- sessions are stored in a relational database. -
memcached
/redis
- sessions are stored in one of these fast, cache based stores. -
dynamodb
- sessions are stored in AWS DynamoDB. -
array
- sessions are stored in a PHP array and will not be persisted.
Prerequisitos del Driver
Base de datos
Al utilizar el driver de sesión database
, necesitarás asegurarte de que tienes una tabla de base de datos para contener los datos de la sesión. Típicamente, esto se incluye en la migración de base de datos predeterminada de Laravel 0001_01_01_000000_create_users_table.php
migración de base de datos; sin embargo, si por alguna razón no tienes una tabla sessions
, puedes usar el comando Artisan make:session-table
para generar esta migración:
php artisan make:session-table php artisan migrate
Redis
Antes de usar sesiones de Redis con Laravel, necesitarás instalar la extensión 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, consulta la documentación de Redis de Laravel.
[!NOTA] La variable de entorno
SESSION_CONNECTION
, o la opciónconnection
en el archivo de configuraciónsession.php
, pueden usarse para especificar qué conexión de Redis se utiliza para el almacenamiento de sesiones.
Interactuando Con la Sesión
Recuperando Datos
Hay dos formas principales de trabajar con datos de sesión en Laravel: el helper global session
y a través de una instancia de Request
. Primero, veamos cómo acceder a la sesión a través de una instancia de Request
, que se puede indicar como tipo en una función anónima de ruta o método del controlador. Recuerda, 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{ /** * Show the profile for the given user. */ 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 recuperas un elemento de la sesión, también puedes 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 pasas una función anónima como el valor predeterminado al método get
y la clave solicitada no existe, se ejecutará la función anónima y se devolverá su resultado:
$value = $request->session()->get('key', 'default'); $value = $request->session()->get('key', function () { return 'default';});
El Helper Global de Sesión
También puedes usar la función PHP global session
para recuperar y almacenar datos en la sesión. Cuando se llama al helper session
con un solo argumento de cadena, devolverá el valor de esa clave de sesión. Cuando se llama al helper con un array de pares clave / valor, esos valores se almacenarán en la sesión:
Route::get('/home', function () { // Retrieve a piece of data from the session... $value = session('key'); // Specifying a default value... $value = session('key', 'default'); // Store a piece of data in the session... session(['key' => 'value']);});
[!NOTA] Hay poca diferencia práctica entre usar la sesión a través de una instancia de solicitud HTTP frente a usar el helper global
session
. Ambos métodos son testables a través del métodoassertSessionHas
que está disponible en todos tus casos de prueba.
Recuperando Todos los Datos de Sesión
Si deseas recuperar todos los datos de la sesión, puedes usar el método all
:
$data = $request->session()->all();
Recuperando una Porción de los Datos de la Sesión
Los métodos only
y except
se pueden utilizar para recuperar un subconjunto de los datos de la sesión:
$data = $request->session()->only(['username', 'email']); $data = $request->session()->except(['username', 'email']);
Determinando si un Elemento Existe en la Sesión
Para determinar si un elemento está presente en la sesión, puedes usar 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
, puedes usar el método exists
:
if ($request->session()->exists('users')) { // ...}
Para determinar si un elemento no está presente en la sesión, puedes usar el método missing
. El método missing
devuelve true
si el elemento no está presente:
if ($request->session()->missing('users')) { // ...}
Almacenando Datos
Para almacenar datos en la sesión, típicamente usarás el método put
de la instancia de la solicitud o el helper global session
:
// Via a request instance...$request->session()->put('key', 'value'); // Via the global "session" helper...session(['key' => 'value']);
Añadiendo valores a la sesión de Array
El método push
se puede usar para añadir un nuevo valor a un valor de sesión que es un array. Por ejemplo, si la clave user.teams
contiene un array de nombres de equipos, puedes añadir un nuevo valor al array de la siguiente manera:
$request->session()->push('user.teams', 'developers');
Recuperando y Eliminando 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');
Incrementando y Decrementando Valores de Sesión
Si los datos de tu sesión contienen un entero que deseas incrementar o decrementar, puedes usar 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);
Flash Data
A veces es posible que desees almacenar elementos en la sesión para la siguiente solicitud. Puedes hacerlo utilizando el método flash
. Los datos almacenados en la sesión utilizando este método estarán disponibles de inmediato y durante la solicitud HTTP posterior. Después de la solicitud HTTP posterior, los datos en flash serán eliminados. Los datos en flash son principalmente útiles para mensajes de estado de corta duración:
$request->session()->flash('status', 'Task was successful!');
Si necesitas persistir tus datos flash durante varias solicitudes, puedes usar el método reflash
, que mantendrá todos los datos flash durante una solicitud adicional. Si solo necesitas mantener datos flash específicos, puedes usar el método keep
:
$request->session()->reflash(); $request->session()->keep(['username', 'email']);
Para persistir tus datos flash solo para la solicitud actual, puedes usar el método now
:
$request->session()->now('status', 'Task was successful!');
Eliminando Datos
El método forget
eliminará un dato de la sesión. Si deseas eliminar todos los datos de la sesión, puedes usar el método flush
:
// Forget a single key...$request->session()->forget('name'); // Forget multiple keys...$request->session()->forget(['name', 'status']); $request->session()->flush();
Regenerando el ID de Sesión
Regenerar el ID de sesión a menudo se hace para prevenir que usuarios malintencionados exploten un ataque de fijación de sesión en tu aplicación.
Laravel regenera automáticamente el ID de sesión durante la autenticación si estás utilizando uno de los kits de inicio de Laravel o Laravel Fortify; sin embargo, si necesitas regenerar el ID de sesión de forma manual, puedes usar el método regenerate
:
$request->session()->regenerate();
Si necesitas regenerar el ID de sesión y eliminar todos los datos de la sesión en una sola declaración, puedes usar el método invalidate
:
$request->session()->invalidate();
Bloqueo de Sesión
[!WARNING] Para utilizar el bloqueo de sesiones, tu aplicación debe estar utilizando un driver de caché que soporte bloqueos atómicos. Actualmente, esos drivers de caché incluyen los drivers
memcached
,dynamodb
,redis
,database
,file
yarray
. Además, no puedes usar el driver de sesióncookie
. Por defecto, Laravel permite que las solicitudes que utilizan la misma sesión se ejecuten de forma concurrente. Así que, por ejemplo, si usas una biblioteca HTTP de JavaScript para hacer dos solicitudes HTTP a tu aplicación, ambas se ejecutarán al mismo tiempo. Para muchas aplicaciones, esto no es un problema; sin embargo, puede ocurrir pérdida de datos de sesión en un pequeño subconjunto de aplicaciones que realizan solicitudes concurrentes a dos endpoints de aplicación diferentes que ambos escriben datos en la sesión. Para mitigar esto, Laravel ofrece una funcionalidad que te permite limitar las solicitudes concurrentes para una sesión dada. Para comenzar, simplemente puedes encadenar el métodoblock
a tu definición de ruta. En este ejemplo, una solicitud entrante al punto final/profile
adquiriría un bloqueo de sesión. Mientras se mantenga este bloqueo, cualquier solicitud entrante a los puntos finales/profile
o/order
que compartan el mismo ID de sesión esperará a que la primera solicitud termine de ejecutarse antes de continuar con 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 número máximo de segundos que se debe mantener el bloqueo de la 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 número de segundos que debe esperar una solicitud mientras intenta obtener un bloqueo de sesión. Se lanzará una Illuminate\Contracts\Cache\LockTimeoutException
si la solicitud no puede obtener un bloqueo de sesión dentro del número dado de segundos.
Si ninguno de estos argumentos es pasado, se obtendrá el bloqueo por un máximo de 10 segundos y las solicitudes esperarán un máximo de 10 segundos mientras intentan obtener un bloqueo:
Route::post('/profile', function () { // ...})->block()
Agregar Controladores de Sesión Personalizados
Implementando el Driver
Si ninguno de los controladores de sesión existentes se adapta a las necesidades de tu aplicación, Laravel permite escribir tu propio manejador de sesión. Tu driver de sesión personalizado debe implementar SessionHandlerInterface
incorporado de PHP. Esta interfaz contiene solo unos pocos métodos simples. Una implementación de MongoDB simulada se ve como la siguiente:
<?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) {}}
[!NOTE]
Laravel no viene con un directorio para contener tus extensiones. Puedes colocarlas donde desees. En este ejemplo, hemos creado un directorioExtensions
para albergar elMongoSessionHandler
. Dado que el propósito de estos métodos no es fácilmente comprensible, cubriamos rápidamente qué hace cada uno de los métodos:
- The
open
method would typically be used in file based session store systems. Since Laravel ships with afile
session driver, you will rarely need to put anything in this method. You can simply leave this method empty. - The
close
method, like theopen
method, can also usually be disregarded. For most drivers, it is not needed. - The
read
method should return the string version of the session data associated with the given$sessionId
. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you. - The
write
method should write the given$data
string associated with the$sessionId
to some persistent storage system, such as MongoDB or another storage system of your choice. Again, you should not perform any serialization - Laravel will have already handled that for you. - The
destroy
method should remove the data associated with the$sessionId
from persistent storage. - The
gc
method should destroy all session data that is older than the given$lifetime
, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty.
Registrando el Driver
Una vez que tu driver haya sido implementado, estás listo para registrarlo con Laravel. Para agregar drivers adicionales al backend de sesión de Laravel, puedes usar el método extend
proporcionado por la facade Session
. Debes llamar al método extend
desde el método boot
de un service provider. Puedes hacer esto desde el 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{ /** * Register any application services. */ public function register(): void { // ... } /** * Bootstrap any application services. */ public function boot(): void { Session::extend('mongo', function (Application $app) { // Return an implementation of SessionHandlerInterface... return new MongoSessionHandler; }); }}
Una vez que el driver de sesión ha sido registrado, puedes especificar el driver mongo
como el driver de sesión de tu aplicación utilizando la variable de entorno SESSION_DRIVER
o dentro del archivo de configuración config/session.php
de la aplicación.