ภาพรวมระบบ (System Overview)
เราจะใช้ Keycloak เป็น Identity Provider (IDP) หลักในการจัดการผู้ใช้งานและการยืนยันตัวตนทั้งหมด โดย Laravel จะทำหน้าที่เป็น Service Provider (SP) ที่เชื่อมต่อกับ Keycloak เพื่อรับข้อมูลผู้ใช้งานมาจัดการภายในแอปพลิเคชัน Laravel ของเรา
สถาปัตยกรรม (Architecture)

ขั้นตอนการตั้งค่าและแนวทางปฏิบัติ (Setup and Best Practices)
1. การเตรียม Keycloak (Keycloak Setup)
รัน Keycloak บน Docker Image เป็น Best Practice เพื่อความสะดวกในการจัดการและ Deployment
1.1 Docker Compose สำหรับ Keycloak (Recommended)
สร้างไฟล์ docker-compose.yml ในโปรเจกต์ของคุณ (หรือแยกออกมาในโฟลเดอร์สำหรับ Infrastructure)
| # docker-compose.yml version: ‘3.8’ services: keycloak: image: quay.io/keycloak/keycloak:latest container_name: keycloak command: start-dev # สำหรับการพัฒนา, ห้ามใช้ใน Production! ports: – “8080:8080” – “8443:8443” # ถ้าต้องการใช้ HTTPS volumes: – ./keycloak-data:/opt/keycloak/data environment: KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: admin KC_HOSTNAME: localhost # หรือ IP Address ของเครื่องคุณ KC_HTTP_PORT: 8080 # พอร์ตที่ Keycloak จะรัน |
1.2 รัน Keycloak
| docker-compose up -d |
คุณควรจะเข้าถึง Keycloak Admin Console ได้ที่ http://localhost:8080 (หรือพอร์ตที่คุณตั้งค่าไว้) ด้วย username admin และรหัสผ่านที่คุณตั้งค่าไว้
1.3 การตั้งค่า Realm และ Client ใน Keycloak
-
สร้าง Realm ใหม่:
- เข้าสู่ Keycloak Admin Console
- คลิกที่
Master(ด้านซ้ายบน) แล้วเลือกAdd realm - ตั้งชื่อ Realm เช่น
LaravelApp
-
สร้าง Client ใหม่:
- ใน Realm ที่สร้างขึ้น
LaravelAppเลือกClients - คลิก
Create client - Client type:
OpenID Connect - Client ID: ตั้งชื่อ
laravel-app(ใช้ใน Laravel config) - Name:
Laravel Application(ชื่อที่แสดง) - Description: (ไม่บังคับ)
- Root URL: URL หลักของแอปพลิเคชัน Laravel ของคุณ เช่น
http://localhost:8000 - Valid Redirect URIs: เพิ่ม
http://localhost:8000/auth/callback(สำคัญมาก!) - Web origins:
http://localhost:8000 - Standard Flow Enabled:
ON - Client authentication:
ON
- ใน Realm ที่สร้างขึ้น
-
สร้าง Credentials สำหรับ Client:
- เมื่อสร้าง Client แล้ว ไปที่แท็บ
Credentials - คุณจะเห็น
Client secretตรงนี้ ให้คัดลอกค่านี้ไปใช้ใน Laravel config
- เมื่อสร้าง Client แล้ว ไปที่แท็บ
2. การตั้งค่า Laravel (Laravel Setup)
2.1 ติดตั้ง Laravel 12
ตรวจสอบให้แน่ใจว่าคุณติดตั้ง Laravel 12 เรียบร้อยแล้วผ่าน Composer
2.2 ติดตั้ง Socialite และ SocialiteProviders/Keycloak
| composer require laravel/socialite socialiteproviders/keycloak |
2.3 ตั้งค่า Environment Variables (.env)
| # Keycloak KEYCLOAK_CLIENT_ID=”laravel-app” KEYCLOAK_CLIENT_SECRET=”<YOUR_KEYCLOAK_CLIENT_SECRET>” # คัดลอกมาจาก Keycloak Client Credentials KEYCLOAK_REDIRECT_URI=”http://127.0.0.1:8000/auth/callback” # ต้องตรงกับ Valid Redirect URI ใน Keycloak KEYCLOAK_BASE_URL=”http://localhost:8080″ KEYCLOAK_REALM=”LaravelApp” |
2.4 ตั้งค่า config/services.php
เพิ่ม Keycloak ลงใน config/services.php
|
‘keycloak’ => [
‘client_id’ => env(‘KEYCLOAK_CLIENT_ID’),
‘client_secret’ => env(‘KEYCLOAK_CLIENT_SECRET’),
‘redirect’ => env(‘KEYCLOAK_REDIRECT_URI’),
‘base_url’ => env(‘KEYCLOAK_BASE_URL’), // e.g., https://auth.yourdomain.com
‘realms’ => env(‘KEYCLOAK_REALM’), // e.g., my-app-realm
],
|
app/Providers/EventServiceProvider.php2.5.1. สร้าง EventServiceProvider ด้วย Artisan:
รันคำสั่งนี้ใน Terminal ของคุณ:
| php artisan make:provider EventServiceProvider |
คำสั่งนี้จะสร้างไฟล์ app/Providers/EventServiceProvider.php ให้คุณ
2.5.2 แก้ไขไฟล์ app/Providers/EventServiceProvider.php: เปิดไฟล์ที่เพิ่งสร้างขึ้นมา และเพิ่ม property $listen เข้าไปเหมือนใน Laravel เวอร์ชันก่อนๆ
| <?php
namespace App\Providers; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider public function boot(): void public function shouldDiscoverEvents(): bool |
2.5.3 ลงทะเบียน Provider ใหม่ใน bootstrap/app.php: นี่คือขั้นตอนที่สำคัญที่สุด หลังจากสร้าง Provider แล้ว เราต้องบอกให้ Laravel รู้จักมันด้วย
เปิดไฟล์ bootstrap/app.php และเพิ่ม EventServiceProvider เข้าไปในส่วนของ withProviders()
| <?php
use Illuminate\Foundation\Application; return Application::configure(basePath: dirname(__DIR__)) |
2.6 สร้าง Database Migration สำหรับผู้ใช้งานและ Log
1. สร้างตาราง Log
- ตาราง
auth_logs: สำหรับบันทึก Login/Logout
| php artisan make:migration create_auth_logs_table |
- แก้ไขไฟล์ Migration:
| // database/migrations/xxxx_xx_xx_xxxxxx_create_auth_logs_table.php public function up(): void { Schema::create(‘auth_logs’, function (Blueprint $table) { $table->id(); $table->foreignId(‘user_id’)->nullable()->constrained()->onDelete(‘set null’); $table->string(‘action’); // e.g., login, logout, login_failed $table->string(‘ip_address’, 45)->nullable(); $table->text(‘user_agent’)->nullable(); $table->string(‘idp_provider’)->nullable(); // e.g., keycloak, google, github $table->timestamps(); }); } |
รายละเอียดคอลัมน์ในตาราง
|
- รัน migration:
| php artisan migrate |
2. สร้าง Controller
| php artisan make:controller Auth/KeycloakAuthController |
3. โค้ดใน KeycloakAuthController.php
| <?php
namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; class KeycloakAuthController extends Controller /** // ค้นหาหรือสร้างผู้ใช้ใหม่ในฐานข้อมูล Laravel // ดึงข้อมูล Provider จาก Token (ถ้ามี) // ทำการ Login ผู้ใช้ใน Laravel // บันทึก Log การ Login สำเร็จ return redirect()->intended(‘/dashboard’); // ไปยังหน้า Dashboard หรือหน้าที่ต้องการ /** Auth::logout(); // สร้าง URL สำหรับ Logout ออกจาก Keycloak ด้วย return redirect($logoutUrl); /** /** |
Best Practice:
updateOrCreate(): เป็นวิธีที่ปลอดภัยและมีประสิทธิภาพในการซิงค์ข้อมูลผู้ใช้จาก Keycloak- Stateless Password: เราไม่เก็บรหัสผ่านจริงใน Laravel แต่สร้างค่าสุ่มขึ้นมาเพื่อ memenuhi constraint ของตาราง
users- Keycloak Logout: การ Logout ที่สมบูรณ์จะต้อง Redirect ไปยัง Endpoint ของ Keycloak ด้วย เพื่อเคลียร์ Session ที่ฝั่ง Keycloak
4. เพิ่มคอลัมน์ keycloak_id
อย่าลืมเพิ่มคอลัมน์ keycloak_id ในตาราง users เพื่อใช้เป็น Unique Identifier ในการเชื่อมโยงกับ Keycloak
| php artisan make:migration add_keycloak_id_to_users_table –table=users |
| // In the new migration file
public function up(): void |
รายละเอียดคอลัมน์ที่เปลี่ยนแปลงในตาราง
|
5. กำหนด Routes
ใน routes/web.php:
| use App\Http\Controllers\Auth\KeycloakAuthController;
Route::get(‘/login’, [KeycloakAuthController::class, ‘redirectToProvider’])->name(‘login’); // ตัวอย่าง Route ที่ต้องการการยืนยันตัวตน |
สรุปแนวทาง Best Practice
- Centralize Identity: ใช้ Keycloak เป็น “Single Source of Truth” สำหรับข้อมูลและการยืนยันตัวตนทั้งหมด
- Infrastructure as Code: บริหารจัดการ Keycloak Server ด้วย Docker Compose หรือ Kubernetes เพื่อความสม่ำเสมอและง่ายต่อการทำซ้ำ
- Secure Configuration: ใช้ Environment Variables สำหรับข้อมูลสำคัญ (Credentials, Hostnames) และไม่ Hardcode ลงในโค้ด
- Decoupled Logout: ทำให้การ Logout เป็นแบบสมบูรณ์โดยเคลียร์ Session ทั้งฝั่ง Laravel และ Keycloak
- Comprehensive Logging: บันทึกทุกกิจกรรมการเข้า-ออกจากระบบ พร้อมข้อมูลแวดล้อม (IP, User Agent) และแหล่งที่มาของ Provider (Google, GitHub) เพื่อการตรวจสอบความปลอดภัย
- Stateless Users in Laravel: Laravel Application ไม่จำเป็นต้องรู้หรือจัดการรหัสผ่านของผู้ใช้เลย ลดความเสี่ยงด้านความปลอดภัยลงอย่างมาก
- Seamless User Sync: ใช้
updateOrCreateเพื่อให้ข้อมูลผู้ใช้ใน Laravel (เช่น ชื่อ, อีเมล) อัปเดตตรงกับข้อมูลใน Keycloak เสมอเมื่อมีการล็อกอิน
แนวทางนี้จะช่วยให้คุณได้ระบบ Authentication ที่แข็งแกร่ง, ยืดหยุ่น, ปลอดภัย และพร้อมสำหรับการใช้งานระดับ Production อย่างแท้จริงครับ!