Skip to content

Latest commit

 

History

History
354 lines (240 loc) · 19.1 KB

session.md

File metadata and controls

354 lines (240 loc) · 19.1 KB

Session HTTP

Pendahuluan

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.

Konfigurasi

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 pada storage/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.

Prasyarat Driver

Database

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

Redis

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 konfigurasi session, opsi connection dapat digunakan untuk menentukan koneksi Redis yang digunakan untuk session.

Berinteraksi dengan Session

Mengambil Data

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';
});

Helper Session Global

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 metode assertSessionHss yang terdapat pada semua kasus/skenario pengujian.

Mengambil Semua Data pada Session

Jika Anda ingin mengambil semua data yang terdapat pada session, Anda dapat menggunakan metode all:

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

Memastikan Apakah Item Terdapat pada Session

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')) {
    //
}

Menyimpan Data

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']);

Mendorong Sebuah Nilai ke dalam Array pada Session

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');

Mengambil & Menghapus Item

Metode pull akan mengambil dan menghapus sebuah item pada session dengan satu statement (perintah):

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

Menambah & Mengurangi Nilai dalam Session

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);

Flash Data

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!');

Menghapus Data

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();

Re-generate ID Session

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();

Pemblokiran Session

Peringatan
Untuk memanfaatkan pemblokiran session, aplikasi Anda harus menggunakan driver cache yang mendukung atomic lock. Saat ini, driver cache tersebut meliputi driver memcached, dynamodb, redis, dan database. Selain itu, Anda tidak boleh menggunakan driver session cookie.

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()

Menambahkan Driver Session yang Kustom

Implementasi Driver

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 direktori Extensions sebagai tempat tinggal MongoSessionHandler.

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 driver file untuk session, Anda akan sangat jarang mengubah metode ini. Anda dapat. Anda dapat membiarkan metode ini kosong.

  • Metode close mirip seperti metode open 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.

Mendaftarkan Driver

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.