Karena aplikasi yang digerakkan dengan HTTP bersifat stateless, session memberikan sebuah cara untuk menyimpan informasi tentang pengguna yang dapat melintasi banyak request. Informasi pengguna seperti ini biasanya ditempatkan pada penyimpanan / backend yang persisten, yang dapat diakses pada request yang berikutnya.
Laravel dilengkapi dengan berbagai session backend yang diakses melalui API yang ekspresif dan terpadu. Dengan dukungan untuk backend-backend populer seperti Memcached, Redis, dan database lain yang termasuk.
File konfigurasi session aplikasi Anda terdapat pada config/session.php
. Pastikan untuk meninjau semua opsi yang tersedia untuk Anda pada file tersebut. Secara default, Laravel dikonfigurasi untuk menggunakan file
sebagai driver session, yang akan berfungsi baik pada kebanyakan aplikasi. Jika aplikasi Anda akan menerapkan load balance—untuk membagi beban kerja aplikasi—ke beberapa server web, Anda sebaiknya memilih penyimpanan terpusat yang dapat diakses oleh semua server, seperti Redis atau database.
Opsi konfigurasi driver
untuk session akan menentukan di mana data session akan disimpan untuk setiap request. Laravel dilengkapi dengan driver-driver hebat yang sudah termasuk di dalam "kemasan"-nya.
file
- session disimpan padastorage/framework/sessions
.cookie
- session disimpan secara aman pada cookie yang terenkripsi.database
- session disimpan pada basis data relasional.memcached
/redis
- session disimpan pada salah satu layanan tersebut, penyimpanan berbasis cache.dynamodb
- session disimpan pada DynamoDB AWS.array
- session disimpan pada sebuah array PHP yang tidak—mungkin—persisten.
Catatan
Driver dengan array utamanya digunakan ketika melakukan pengujian untuk mencegah data yang disimpan pada session menjadi persisten.
Ketika menggunakan driver database
untuk session, Anda akan membutuhkan sebuah tabel untuk menampung rekaman session. Contoh deklarasi Schema
untuk tabel tersebut dapat dilihat pada kode di bawah ini:
Schema::create('sessions', function ($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();
});
Anda dapat menggunakan perintah Artisan session:table
untuk menghasilkan migration tersebut. Untuk mempelajari lebih lanjut tentang migration basis data, Anda dapat membacanya secara utuh pada dokumentasi migration:
php artisan session:table
php artisan migrate
Sebelum menggunakan session Redis pada Laravel, Anda harus menginstal ekstensi PHP bernama PhpRedis melalui PECL atau package predis/predis
(~1.0) melalui Composer. Untuk informasi lebih lanjut tentang konfigurasi Redis, silahkan mempelajari dokumentasi Redis milik Laravel.
Catatan
Pada file konfigurasisession
, opsiconnection
dapat digunakan untuk menentukan koneksi Redis yang digunakan untuk session.
Terdapat dua cara utama untuk bekerja dengan data session pada Laravel: helper global session
dan melalui instance Request
. Pertama-tama, mari lihat cara mengakses session melalui instance Request
yang dapat di-type-hint pada closure route atau metode controller. Perlu diingat, dependensi pada metode controller telah terinjeksi secara otomatis melalui service container Laravel:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Menampilkan profil pengguna.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function show(Request $request, $id)
{
$value = $request->session()->get('key');
//
}
}
Ketika anda mengambil (retrieve) sebuah item pada sessiom, Anda juga dapat mengoper nilai default sebagai argumen kedua pada metode get
. Nilai default ini akan dikembalikan jika nama kunci yang sudah ditentukan tidak ditemukan pada session. Jika Anda mengoper sebuah closure sebagai nilai default, maka closure tersebut akan dieksekusi jika nama kunci yang ditentukan tidak terdapat pada session:
$value = $request->session()->get('key', 'default');
$value = $request->session()->get('key', function () {
return 'default';
});
Anda juga dapat menggunakan fungsi global PHP bernama session
untuk mengambil dan menyimpan data pada session. Ketika helper session
dipanggil dengan satu argumen string, fungsi tersebut akan mengembalikan nilai dari nama kunci pada session. Namun, ketika helper tersebut dipanggil dengan argumen array pasangan kunci-nilai (key-value pairs / array asosiatif), Nilai-nilai tersebut akan disimpan pada session:
Route::get('/beranda', function () {
// Mengambil data dari session...
$value = session('nama');
// Menentukan nilai default...
$value = session('nama', 'Zain');
// Menyimpan sebuah data pada session...
session(['nama' => 'Zain Adam']);
});
Catatan
Dalam praktiknya, terdapat sebuah perbedaan kecil pada pemanfaatan session antara menggunakan instance HTTP request dan helper global session. Ke-dua metode tersebut dapat dimasukkan ke dalam pengujian melalui metodeassertSessionHss
yang terdapat pada semua kasus/skenario pengujian.
Jika Anda ingin mengambil semua data yang terdapat pada session, Anda dapat menggunakan metode all
:
$data = $request->session()->all();
Untuk memastikan apakah sebuah item (data) telah terdapat di dalam session, Anda dapat menggunakan metode has
. Metode has
mengembalikan nilai true
jika item tersebut telah terdapat di dalam session dan tidak bernilai null
:
if ($request->session()->has('pengguna')) {
//
}
Untuk memastikan apakah sebuah item telah terdapat di dalam session walaupun bernilai null
, Anda dapat menggunakan metode exists
:
if ($request->session()->exists('pengguna')) {
//
}
Untuk menentukan apakah sebuah item tidak terdapat di dalam session, Anda dapat menggunakan metode missing
. Metode missing
mengembalikan nilai true
jika item tersebut tidak terdapat di dalam session:
if ($request->session()->missing('pengguna')) {
//
}
Untuk menyimpan data ke dalam session, Anda biasanya akan menggunakan metode put
milik instance request atau helper global session
:
// Melalui instance request...
$request->session()->put('nama', 'Zain');
// Melalui the helper global "session"...
session(['nama' => 'Zain']);
Metode push
dapat digunakan untuk mendorong (menambahkan item di ujung array) sebuah nilai baru ke dalam nilai session yang berjenis array. Sebagai contoh, jika sebuah kunci pengguna.daftarTeman
adalah sebuah array yang berisi nama-nama teman milik pengguna, Anda dapat memasukkan sebuah nilai baru (misalnya nama teman yang baru) ke dalam array tersebut:
$request->session()->push('pengguna.daftarTeman', 'Taylor Otwell');
Metode pull
akan mengambil dan menghapus sebuah item pada session dengan satu statement (perintah):
$value = $request->session()->pull('key', 'default');
Jika terdapat data berjenis integer pada session Anda yang nilainya ingin ditambah atau dikurangi, Anda dapat menggunakan metode increment
dan decrement
:
$request->session()->increment('count');
$request->session()->increment('count', $incrementBy = 2);
$request->session()->decrement('count');
$request->session()->decrement('count', $decrementBy = 2);
Terkadang Anda ingin menyimpan item pada session yang hanya tersedia pada request yang berikutnya saja. Anda dapat melakukannya dengan menggunakan metode flash
. Dengan menggunakan metode tersebut, data yang tersimpan pada session hanya akan tersedia pada request HTTP yang berikutnya saja. Setelah HTTP request tersebut berakhir, data yang telah di-flash tadi akan terhapus. Flash data sangat berguna untuk pesan status—atau informasi dari sistem—yang berumur singkat:
$request->session()->flash('status', 'Email telah terkirim!');
Jika Anda ingin mempertahankan data flash untuk beberapa request, Anda dapat menggunakan metode reflash
yang akan menjaga semua data flash Anda pada request kedepannya. Jika Anda hanya perlu untuk mempertahankan data flash tertentu saja, Anda dapat menggunakan metode keep
:
$request->session()->reflash();
$request->session()->keep(['username', 'email']);
Untuk mempertahankan flash data pada request saat ini saja, Anda dapat menggunakan metode now
:
$request->session()->now('status', 'Email telah terkirim!');
Metode forget
akan menghapus sebuah data pada session. Jika Anda ingin menghapus semua data, Anda dapat menggunakan metode flush
:
// "Forget" key tunggal...
$request->session()->forget('nama');
// "Forget" beberapa key...
$request->session()->forget('nama', 'status']);
$request->session()->flush();
Membuat ulang (re-generate) ID session sering dilakukan untuk mencegah pengguna jahat yang mengeksploitasi serangan [Session Fixation] (https://owasp.org/www-community/attacks/Session_fixation) pada aplikasi Anda.
Laravel secara otomatis membuat ulang ID session pada saat autentikasi jika Anda menggunakan salah satu dari peralatan awal aplikasi Laravel atau Laravel Fortify; namun, jika Anda perlu membuat ulang ID session secara manual, Anda dapat menggunakan metode regenerate
:
$request->session()->regenerate();
Jika Anda perlu membuat ulang ID session dan menghapus semua data pada session dalam satu pernyataan, Anda dapat menggunakan metode invalidate
:
$request->session()->invalidate();
Peringatan
Untuk memanfaatkan pemblokiran session, aplikasi Anda harus menggunakan driver cache yang mendukung atomic lock. Saat ini, driver cache tersebut meliputi drivermemcached
,dynamodb
,redis
, dandatabase
. Selain itu, Anda tidak boleh menggunakan driver sessioncookie
.
Secara default, Laravel mengizinkan semua request untuk menggunakan session yang sama untuk dieksekusi secara bersamaan. Sebagai contoh, jika Anda menggunakan sebuah pustaka HTTP JavaScript untuk membuat dua request HTTP ke aplikasi Anda yang dieksekusi pada waktu yang sama. Untuk kebanyakan aplikasi, hal ini bukanlah sebuah masalah; walaupun begitu, hal tersebut dapat menyebabkan session data loss/inkonsistensi data pada halaman tersebut karena membuat beberapa request secara bersamaan ke dua endpoint berbeda dan masing-masing endpoint dapat menulis data pada session.
Untuk mengatasi hal ini, Laravel menyediakan fungsionalitas yang memungkinkan Anda untuk membatasi permintaan bersamaan untuk sesi tertentu. Untuk memulai, Anda dapat dengan mudah merantai metode block
ke dalam definisi rute Anda. Dalam contoh ini, permintaan yang masuk ke titik akhir /profile
akan mendapatkan kunci sesi. Sementara kunci ini ditahan, setiap permintaan yang masuk ke titik akhir /profile
atau /order
yang memiliki ID sesi yang sama akan menunggu permintaan pertama selesai dieksekusi sebelum melanjutkan eksekusi:
Untuk memitigasi hal ini, Laravel menyediakan fungsionalitas yang memungkinkan Anda untuk membatasi request yang bersamaan untuk session tertentu. Untuk melakukannya, Anda dapat merantai metode block
pada pendefinisian rute Anda. Pada contoh ini, sebuah request masuk ke endpoint /profile
akan mendapatkan gembok session. Ketika penguncian terjadi, request apapun yang masuk ke endpoint /profile
atau /order
yang berbagi ID session yang sama akan menunggu request pertama selesai dieksekusi terlebih dahulu sebelum mengeksekusi request yang selanjutnya:
Route::post('/profil', function () {
//
})->block($lockSeconds = 10, $waitSeconds = 10)
Route::post('/order', function () {
//
})->block($lockSeconds = 10, $waitSeconds = 10)
Metode block
menerima dua argumen opsional. Argumen pertama yang diterima oleh metode block
adalah durasi penguncian maksimal (dalam detik) yang dapat dilakukan. Tentu saja, jika request telah selesai dieksekusi sebelum durasi maksimal yang ditentukan, maka gembok akan dibuka lebih awal.
Argumen kedua yang diterima oleh metode block
adalah jumlah detik yang harus ditunggu oleh request ketika ingin melakukan penguncian session. Sebuah Illuminate\Contracts\Cache\LockTimeoutException
akan dilemparkan jika request tersebut tidak berhasik mendapatkan gembok session untuk dirinya ketika masa tunggu telah berakhir.
Jika tidak ada argumen yang dioper, penguncian akan diperoleh selama maksimum 10 detik dan permintaan akan menunggu maksimum 10 detik saat mencoba mendapatkan gembok:
Route::post('/profil', function () {
//
})->block()
Jika pada driver session yang tersedia tidak cocok untuk kebutuhan aplikasi Anda, Laravel memungkinkan Anda untuk menulis penanganan session Anda sendiri. Driver session kustom harus mengimplementasikan built-in SessionHandlerInterface
milik PHP. Interface tersebut memuat beberapa metode sederhana. Sebuah implementasi MonggoDB akan terlihat seperti berikut:
<?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) {}
}
Catatan
Laravel tidak menyertakan direktori untuk menampung Ekstensi Anda. Anda bebas menempatkannya di mana saja yang Anda suka. Pada contoh ini, kita telah membuat sebuah direktoriExtensions
sebagai tempat tinggalMongoSessionHandler
.
Karena tujuan dari metode-metode di atas tidak mudah dimengerti, mari kita bahas secara singkat, apa yang dilakukan oleh masing-masing metode:
-
Metode
open
biasanya digunakan pada sistem penyimpanan session berbasis file, Karena Laravel disertai driverfile
untuk session, Anda akan sangat jarang mengubah metode ini. Anda dapat. Anda dapat membiarkan metode ini kosong. -
Metode
close
mirip seperti metodeopen
yang biasanya dapat diabaikan. Untuk kebanyakan, hal ini tidak diperlukan. -
Metode
read
harus mengembalikan data session dalam bentuk string pada$sessiomId
yang terkait. Anda tidak perlu melakukan serialisasi atau pengkodean lainnya ketika mengambil atau menyimpan data session dalam driver Anda. Laravel akan melakukan serialisasi untuk Anda. -
Metode
write
harus menuliskan string$data
yang diberikan dengan$sessionId
yang terkait ke sistem penyimpanan persisten, seperti MongoDB atau sistem penyimpanan lain yang Anda pilih. Sekali lagi, Anda tidak perlu melakukan serialisasi apa pun - Laravel sudah menanganinya untuk Anda. -
Metode
destroy
harus menghapus data dengan$sessionId
yang terkait pada penyimpanan persisten. -
Metode
gc
harus "menghancurkan" semua data session yang usianya melebihi$lifetime
yang ditentukan yang mana adalah timestamp UNIX. Untuk sistem peng-kedaluawarsa-an secara mandiri seperti Memcached dan Redis, metode ini dapat dibiarkan kosong.
Setelah driver Anda diimplementasikan, Anda siap untuk mendaftarkannya ke Laravel. Untuk menambahkan driver tambahan ke backend session milik Laravel, Anda dapat menggunakan metode extend
yang disediakan oleh facade Session
. Anda harus memanggil metode extend
dari metode boot
pada service provider. Anda dapat mendaftarkannya pada App\Providers\AppServiceProvider
yang sudah ada atau membuat provider yang baru:
<?php
namespace App\Providers;
use App\Extensions\MongoSessionHandler;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;
class SessionServiceProvider extends ServiceProvider
{
/**
* Mendaftarkan layanan pada aplikasi.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap layanan yang terdapat pada aplikasi.
*
* @return void
*/
public function boot()
{
Session::extend('mongo', function ($app) {
// Mengembalikan sebuah implementasi dari SessionHandlerInterface...
return new MongoSessionHandler;
});
}
}
Setelah driver session didaftarkan, Anda dapat menggunakan driver mongo
pada file konfigurasi config/session.php
.