Pendahuluan — alur sudah rapi, siapa yang boleh masuk?
Di Controller, Service & Eloquent (#58) kamu sudah punya alur rapi: penjaga input, pengatur kode, layanan, dan penyimpanan. Artikel ini adalah #59 (ini) — langkah keempat stack Laravel di Seri 4.
Ide barunya: tidak semua orang boleh memanggil API. Kita butuh otentikasi — memastikan “siapa kamu” sebelum pintu dibuka. Awam: bukti masuk (sering disebut token) seperti kartu anggota perpustakaan.
Awam: bayangkan loket khusus staf. Siapa saja boleh lihat katalog umum. Tapi menambah buku hanya untuk yang sudah login dan membawa kartu anggota (bukti masuk). Tanpa kartu: ditolak — bukan karena data kotor, tapi karena belum diizinkan.
Prasyarat: sudah baca Controller, Service & Eloquent (#58) — paham controller/service dan status JSON. Domain tetap perpustakaan mini. Pakai Laravel 11+ — ide login + bukti masuk di sini berlaku di versi modern.
Istilah — Auth, login, bukti masuk
| Istilah | Arti awam | Contoh singkat |
|---|---|---|
| Otentikasi (auth) | Memastikan “siapa kamu” sebelum akses | Login email + kata sandi |
| Login | Proses membuktikan identitas (biasanya email/sandi) | POST /api/login |
| Bukti masuk (token) | Kartu sementara setelah login — dibawa di permintaan berikutnya | String acak di header |
| Status 401 | “Belum diizinkan” — pintu ketemu, tapi kamu belum terbukti | 401 tanpa bukti / bukti salah |
| Pemeriksa pintu | Lapisan yang cek bukti masuk sebelum controller jalan (sering disebut middleware) | Cek header dulu, baru store |
Jangan hafal semua dulu. Cukup: login mengeluarkan bukti, permintaan berikutnya membawa bukti, tanpa bukti = 401.
Bedakan dari 422 di Request & Form Request (#57): 422 = data kotor; 401 = kamu belum diizinkan.
Kenapa belum langsung paket Laravel?
Kenapa belum langsung paket bukti masuk Laravel (sering disebut Sanctum) / login bawaan? Karena ide “cek identitas dulu, baru lanjut” bisa dirasakan di PHP biasa. Kalau ide-nya sudah “klik”, cuplikan Laravel nanti terasa seperti bungkus yang sama.
<?php
// Anggota sederhana (bukan database sungguhan).
$anggota = [
"email" => "staf@perpustakaan.test",
"sandi" => "rahasia123",
];
$input = [
"email" => "staf@perpustakaan.test",
"sandi" => "salah",
];
header("Content-Type: application/json; charset=utf-8");
if ($input["email"] !== $anggota["email"] || $input["sandi"] !== $anggota["sandi"]) {
http_response_code(401);
echo json_encode(["pesan" => "Belum diizinkan — email atau sandi salah"], JSON_UNESCAPED_UNICODE), PHP_EOL;
exit;
}
$bukti = "kartu-".bin2hex(random_bytes(8));
http_response_code(200);
echo json_encode(["ok" => true, "bukti_masuk" => $bukti], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), PHP_EOL;
Output:
{"pesan":"Belum diizinkan — email atau sandi salah"}
Awam: status 401 artinya “pintu ketemu, tapi kamu belum terbukti”. Sandi di contoh disimpan polos supaya mudah dibaca — di dunia nyata sandi disimpan terenkripsi (tidak dibaca apa adanya). bin2hex(random_bytes(...)) hanya cara membuat teks acak untuk kartu — tidak perlu dihafal dulu.
Login bersih — dapat bukti masuk
Kalau email dan sandi cocok, sistem mengeluarkan bukti:
<?php
$anggota = [
"email" => "staf@perpustakaan.test",
"sandi" => "rahasia123",
];
$input = [
"email" => "staf@perpustakaan.test",
"sandi" => "rahasia123",
];
header("Content-Type: application/json; charset=utf-8");
if ($input["email"] !== $anggota["email"] || $input["sandi"] !== $anggota["sandi"]) {
http_response_code(401);
echo json_encode(["pesan" => "Belum diizinkan — email atau sandi salah"], JSON_UNESCAPED_UNICODE), PHP_EOL;
exit;
}
$bukti = "kartu-".bin2hex(random_bytes(8));
http_response_code(200);
echo json_encode(["ok" => true, "bukti_masuk" => $bukti], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), PHP_EOL;
Output (bentuknya mirip; angka di bukti berubah tiap jalan):
{
"ok": true,
"bukti_masuk": "kartu-ab12cd34ef56..."
}
Awam: simpan bukti ini di sisi pemanggil (aplikasi / alat uji), lalu kirim lagi saat menambah buku.
Pintu terlindungi — cek bukti dulu
Sebelum controller menyimpan buku, pemeriksa pintu membaca bukti masuk:
<?php
$buktiValid = "kartu-abc123";
$buktiDariHeader = ""; // kosong = belum bawa kartu
header("Content-Type: application/json; charset=utf-8");
if ($buktiDariHeader === "" || $buktiDariHeader !== $buktiValid) {
http_response_code(401);
echo json_encode(["pesan" => "Belum diizinkan — bawa bukti masuk"], JSON_UNESCAPED_UNICODE), PHP_EOL;
exit;
}
http_response_code(201);
echo json_encode(["ok" => true, "buku" => ["judul" => "Belajar PHP"]], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), PHP_EOL;
Output:
{"pesan":"Belum diizinkan — bawa bukti masuk"}
Awam: ini “pemeriksa pintu” — ide yang sama dengan middleware di Laravel: cek dulu, baru lanjut ke pengatur kode.
Laravel — login & bukti masuk (cuplikan)
Di project Laravel, cuplikan tipikal memakai penjaga Form Request + layanan auth. File ini bukan dijalankan dengan php file.php:
<?php
// Cuplikan Laravel (bukan file mandiri) — login mengeluarkan bukti masuk.
namespace App\Http\Controllers;
use App\Http\Requests\LoginRequest;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
public function login(LoginRequest $request): JsonResponse
{
$user = User::query()->where('email', $request->validated('email'))->first();
if (! $user || ! Hash::check($request->validated('sandi'), $user->password)) {
return response()->json(['pesan' => 'Belum diizinkan — email atau sandi salah'], 401);
}
// createToken = cara Laravel (Sanctum) membuat bukti masuk API.
$bukti = $user->createToken('api-perpustakaan')->plainTextToken;
return response()->json(['ok' => true, 'bukti_masuk' => $bukti], 200);
}
}
Awam:
LoginRequest= penjaga isian login (ide Form Request dari Request & Form Request (#57))JsonResponse= tipe jawaban “ini JSON” (boleh diabaikan dulu kalau masih asing)Hash::check= bandingkan sandi input dengan sandi tersimpan (yang sudah dienkripsi)createToken(...)= buat bukti masuk;plainTextToken= teks bukti yang dikirim ke pemanggil (hanya tampil sekali)- Sanctum = paket Laravel yang biasa dipakai untuk bukti masuk API — detail pasang-pasangnya bisa dipelajari nanti; di sini cukup paham alurnya
<?php
// Cuplikan Laravel — route terlindungi.
use App\Http\Controllers\BukuController;
use Illuminate\Support\Facades\Route;
// auth:sanctum = pemeriksa pintu: wajib bawa bukti masuk yang valid.
Route::post('/api/buku', [BukuController::class, 'store'])
->middleware('auth:sanctum');
Awam: pemanggil biasanya mengirim header Authorization: Bearer <bukti>. Authorization = kotak di header untuk “siapa yang meminta”. Bearer artinya “ini bukti yang saya bawa”. Tanpa itu (atau salah): Laravel menjawab 401.
Controller store tetap tipis seperti di Controller, Service & Eloquent (#58) — yang baru: pintu di depannya sudah dikunci.
Pola Dasar — Auth API
-
1
Rapikan alur dulu Penjaga + controller/service sudah berdiri (lihat Controller, Service & Eloquent (#58)).
-
2
Sediakan login Cek email/sandi — gagal =
401, sukses = bukti masuk. -
3
Lindungi pintu yang sensitif Misalnya
POST /api/bukuwajib bukti; katalog publik boleh tetap terbuka. -
4
Bawa bukti di setiap permintaan terlindungi Header Authorization (tempat bukti) + Bearer + teks bukti.
-
5
Baru satukan jadi proyek utuh Berikutnya: Capstone — merangkai routing, validasi, controller/service, dan auth jadi API perpustakaan lengkap.
Kode lengkap — demo mandiri
Simpan sebagai laravel_auth_api_demo.php, lalu jalankan php laravel_auth_api_demo.php:
<?php
declare(strict_types=1);
$anggota = [
"email" => "staf@perpustakaan.test",
"sandi" => "rahasia123",
];
$buktiAktif = null;
function login(array $input, array $anggota): array
{
if (($input["email"] ?? "") !== $anggota["email"] || ($input["sandi"] ?? "") !== $anggota["sandi"]) {
return ["status" => 401, "body" => ["pesan" => "Belum diizinkan — email atau sandi salah"]];
}
$bukti = "kartu-".bin2hex(random_bytes(4));
return ["status" => 200, "body" => ["ok" => true, "bukti_masuk" => $bukti]];
}
function tambahBuku(?string $buktiHeader, ?string $buktiAktif): array
{
if ($buktiHeader === null || $buktiHeader === "" || $buktiHeader !== $buktiAktif) {
return ["status" => 401, "body" => ["pesan" => "Belum diizinkan — bawa bukti masuk"]];
}
return ["status" => 201, "body" => ["ok" => true, "buku" => ["judul" => "Belajar PHP", "tahun" => 2024]]];
}
function demo(string $judul, callable $aksi): void
{
echo "=== {$judul} ===", PHP_EOL;
$hasil = $aksi();
echo "status: ", $hasil["status"], PHP_EOL;
echo json_encode($hasil["body"], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), PHP_EOL, PHP_EOL;
}
demo("Login kotor -> 401", function () use ($anggota) {
return login(["email" => "staf@perpustakaan.test", "sandi" => "salah"], $anggota);
});
demo("Login bersih -> 200 + bukti", function () use ($anggota, &$buktiAktif) {
$hasil = login(["email" => "staf@perpustakaan.test", "sandi" => "rahasia123"], $anggota);
if (($hasil["body"]["bukti_masuk"] ?? null) !== null) {
$buktiAktif = $hasil["body"]["bukti_masuk"];
}
return $hasil;
});
demo("Tanpa bukti -> 401", function () use (&$buktiAktif) {
return tambahBuku(null, $buktiAktif);
});
demo("Dengan bukti -> 201", function () use (&$buktiAktif) {
return tambahBuku($buktiAktif, $buktiAktif);
});
Awam: demo(...) hanya membungkus output di terminal. callable = sesuatu yang bisa dipanggil seperti fungsi. Baris declare(strict_types=1); membuat tipe data lebih ketat — boleh diikuti, tidak wajib dihafal dulu. Alur yang penting: login gagal/sukses, lalu pintu dengan/ tanpa bukti.
Kesalahan umum
| Gejala | Penyebab tipikal | Perbaikan awam |
|---|---|---|
| Selalu 401 padahal sudah login | Bukti tidak dikirim / salah header | Kirim Authorization: Bearer <bukti> |
| Bingung 401 vs 422 | Mencampur “belum diizinkan” dengan “data kotor” | 401 = identitas; 422 = isian |
| Sandi tersimpan polos | Tidak memakai Hash (pembanding sandi terenkripsi) | Simpan sandi terenkripsi lewat Hash |
| Semua route dikunci | Katalog publik ikut pemeriksa pintu (middleware) | Kunci hanya yang sensitif (misalnya POST) |
Latihan singkat
- Ubah demo: tambah kasus “bukti palsu” (string acak) dan pastikan status tetap 401.
- Jelaskan ke teman (tanpa jargon): beda 401 dan 422 dengan analogi loket perpustakaan.
- Tulis satu kalimat: apa yang terjadi dari login sukses sampai
POST /api/bukudengan bukti masuk.
FAQ singkat
Apa bedanya auth dan validasi?
Validasi cek “apakah isian masuk akal”. Auth cek “apakah kamu yang berhak”. Keduanya sering berurutan: bukti dulu, baru isian — atau sebaliknya tergantung desain, tapi perannya beda.
Haruskah semua API pakai bukti masuk?
Tidak. Baca katalog boleh publik. Menambah/mengubah data biasanya dikunci.
Token / bukti masuk aman digeser ke orang lain?
Tidak. Siapa yang punya bukti = dianggap kamu. Jaga seperti kunci.
Lanjut ke mana?
Berikutnya: Capstone — merangkai routing, validasi, controller/service/Eloquent, dan auth jadi API perpustakaan yang utuh.
Kesimpulan
Kamu sudah menambah kunci di depan alur: login mengeluarkan bukti masuk, pintu sensitif memeriksa bukti, tanpa bukti = 401. Alur dari Controller, Service & Eloquent (#58) tetap dipakai — hanya pintunya yang dikunci.
Seri 4 progress: langkah #59 (ini) · 7/8 menuju Capstone Laravel · stack Laravel 4/5 · prasyarat: Controller, Service & Eloquent (#58) LIVE. Berikutnya: Capstone API perpustakaan (merangkai semua langkah).