ข้ามไปยังเนื้อหาหลัก
คู่มือระบบ เนื้อหาผ่านการตรวจสอบแล้ว

การใช้ Middleware สำหรับ Authentication

บทความนี้กล่าวถึงการใช้ Middleware ใน PHP สำหรับจัดการ Authentication โดยเฉพาะการตรวจสอบ API Key ก่อนอนุญาตให้เข้าถึง Endpoint ซึ่งมีข้อดีคือช่วยให้โค้ดมีความ r...

การใช้ Middleware สำหรับ Authentication

ในบทที่แล้ว เราได้เรียนรู้เกี่ยวกับการสร้าง Middleware ใน PHP และวิธีการใช้งานเบื้องต้น ในบทนี้ เราจะนำความรู้เหล่านั้นมาประยุกต์ใช้กับการทำ Authentication หรือการตรวจสอบสิทธิ์การเข้าถึง API ของเรา โดยจะเน้นไปที่การใช้ Middleware เพื่อตรวจสอบ API Key ก่อนที่จะอนุญาตให้เข้าถึง Endpoint ที่ต้องการ

ทำไมต้องใช้ Middleware สำหรับ Authentication?

การใช้ Middleware สำหรับ Authentication มีข้อดีหลายประการ:

  • Reusable Code: เราสามารถเขียน Logic การตรวจสอบสิทธิ์เพียงครั้งเดียวและนำไปใช้กับหลาย Endpoint ได้
  • Centralized Logic: การจัดการ Authentication Logic อยู่ในที่เดียว ทำให้ง่ายต่อการแก้ไขและบำรุงรักษา
  • Clean Code: ช่วยให้ Controller หรือ Handler ของ Endpoint มีความสะอาดและมุ่งเน้นไปที่ Business Logic หลัก
  • Flexible: สามารถปรับเปลี่ยน Logic การตรวจสอบสิทธิ์ได้ง่าย โดยไม่ต้องแก้ไข Code ใน Controller

การตรวจสอบ API Key ใน Middleware

ขั้นตอนแรกคือการสร้าง Middleware ที่จะทำหน้าที่ตรวจสอบ API Key ที่ส่งมาพร้อมกับ Request ตัวอย่างเช่น เราจะตรวจสอบว่ามี Header ชื่อ X-API-Key หรือไม่ และมีค่าตรงกับ API Key ที่เรากำหนดไว้หรือไม่

<?php

class ApiKeyMiddleware {
  private $apiKey;

  public function __construct(string $apiKey) {
    $this->apiKey = $apiKey;
  }

  public function handle($request, $next) {
    $apiKeyHeader = $request->getHeader('X-API-Key');

    if (empty($apiKeyHeader)) {
      // ไม่พบ API Key ใน Header
      return $this->errorResponse('API Key is required', 401);
    }

    $apiKey = $apiKeyHeader[0]; // ดึงค่า API Key จาก Array

    if ($apiKey !== $this->apiKey) {
      // API Key ไม่ถูกต้อง
      return $this->errorResponse('Invalid API Key', 403);
    }

    // API Key ถูกต้อง เรียก Handler ถัดไป
    return $next($request);
  }

  private function errorResponse(string $message, int $statusCode) {
    header('Content-Type: application/json');
    http_response_code($statusCode);
    echo json_encode(['error' => $message]);
    return; // สำคัญ: ต้อง return เพื่อหยุดการทำงาน
  }
}

คำอธิบาย Code:

  • Class ApiKeyMiddleware รับค่า API Key ผ่าน Constructor
  • Method handle รับ Request และ Closure $next เป็น Parameter
  • ตรวจสอบว่ามี Header ชื่อ X-API-Key หรือไม่ ถ้าไม่มีให้ส่ง Error Response กลับไป
  • ตรวจสอบว่าค่าของ X-API-Key ตรงกับ API Key ที่กำหนดไว้หรือไม่ ถ้าไม่ตรงให้ส่ง Error Response กลับไป
  • ถ้า API Key ถูกต้อง ให้เรียก Closure $next เพื่อส่ง Request ไปยัง Handler ถัดไป
  • Method errorResponse สร้าง JSON Response ที่มี Error Message และ HTTP Status Code

ข้อควรระวัง:

  • อย่า Hardcode API Key ใน Code ควรเก็บไว้ใน Environment Variable หรือ Configuration File
  • ควรใช้ HTTPS เพื่อป้องกันการดักจับ API Key

การให้สิทธิ์การเข้าถึง (Authorization)

นอกจากการตรวจสอบว่า API Key ถูกต้องแล้ว เราอาจต้องการให้สิทธิ์การเข้าถึงที่แตกต่างกัน ขึ้นอยู่กับ API Key ที่ใช้ ตัวอย่างเช่น API Key สำหรับ Admin อาจสามารถเข้าถึง Endpoint ได้ทุก Endpoint ในขณะที่ API Key สำหรับ User ทั่วไปอาจเข้าถึงได้เฉพาะบาง Endpoint เท่านั้น

เราสามารถ Implement Logic นี้ได้ใน Middleware โดยการตรวจสอบ API Key และกำหนด Role หรือ Permission ให้กับ Request จากนั้นจึงตรวจสอบว่า Request นั้นมีสิทธิ์ในการเข้าถึง Endpoint ที่ต้องการหรือไม่

<?php

class ApiKeyMiddleware {
  private $apiKeys = [
    'admin' => 'ADMIN_API_KEY',
    'user' => 'USER_API_KEY',
  ];

  private $roles = [
    'ADMIN_API_KEY' => ['role' => 'admin', 'permissions' => ['*']], // admin มีสิทธิ์ทุกอย่าง
    'USER_API_KEY' => ['role' => 'user', 'permissions' => ['read', 'write']], // user มีสิทธิ์อ่าน/เขียน
  ];


  public function handle($request, $next, $requiredPermission = null) {
    $apiKeyHeader = $request->getHeader('X-API-Key');

    if (empty($apiKeyHeader)) {
      return $this->errorResponse('API Key is required', 401);
    }

    $apiKey = $apiKeyHeader[0];

    if (!in_array($apiKey, array_values($this->apiKeys))) {
      return $this->errorResponse('Invalid API Key', 403);
    }

    // ดึง role และ permission จาก API Key
    $roleData = $this->roles[$apiKey];
    $request->attributes->set('role', $roleData['role']); // เก็บ role ไว้ใน request
    $request->attributes->set('permissions', $roleData['permissions']); // เก็บ permission ไว้ใน request

    if ($requiredPermission !== null && !in_array($requiredPermission, $roleData['permissions'])) {
      return $this->errorResponse('Unauthorized', 403);
    }


    return $next($request);
  }

  private function errorResponse(string $message, int $statusCode) {
    header('Content-Type: application/json');
    http_response_code($statusCode);
    echo json_encode(['error' => $message]);
    return;
  }
}

คำอธิบาย Code:

  • $apiKeys เก็บ API Key แต่ละประเภท (admin, user)
  • $roles เก็บ Role และ Permission ของแต่ละ API Key
  • Method handle รับ Parameter เพิ่มเติมคือ $requiredPermission ซึ่งเป็น Permission ที่ Endpoint นั้นต้องการ
  • ตรวจสอบว่า API Key มีอยู่ใน $roles หรือไม่
  • ถ้ามี ให้ดึง Role และ Permission ของ API Key นั้น
  • ตรวจสอบว่า Request นั้นมี Permission ที่ Endpoint ต้องการหรือไม่ ถ้าไม่มีให้ส่ง Error Response กลับไป
  • เก็บ Role และ Permission ไว้ใน Request Attribute เพื่อให้ Controller สามารถนำไปใช้ได้

ตัวอย่างการใช้งาน:

<?php

// ตัวอย่างการใช้งานใน Controller
$apiKeyMiddleware = new ApiKeyMiddleware();

// Endpoint ที่ต้องการ Permission 'read'
$response = $apiKeyMiddleware->handle($request, function ($request) {
  // Logic ของ Endpoint
  $role = $request->attributes->get('role');
  $permissions = $request->attributes->get('permissions');

  // ตรวจสอบ Role และ Permission เพิ่มเติม (ถ้าต้องการ)
  if ($role === 'admin' || in_array('read', $permissions)) {
    return json_encode(['message' => 'Data retrieved successfully']);
  } else {
    return json_encode(['error' => 'Unauthorized'], 403);
  }
}, 'read');

echo $response;

การส่ง Error Response

เมื่อเกิด Error ใน Middleware เช่น API Key ไม่ถูกต้อง หรือไม่มีสิทธิ์การเข้าถึง เราจะต้องส่ง Error Response กลับไปยัง Client เพื่อแจ้งให้ทราบถึงปัญหาที่เกิดขึ้น

Error Response ควรมีข้อมูลที่จำเป็น เช่น HTTP Status Code และ Error Message

HTTP Status Codes ที่ควรใช้:

  • 401 Unauthorized: ใช้เมื่อ API Key ไม่ถูกต้อง หรือไม่มี API Key ส่งมา
  • 403 Forbidden: ใช้เมื่อ API Key ถูกต้อง แต่ไม่มีสิทธิ์ในการเข้าถึง Endpoint นั้น

ตัวอย่าง Error Response (JSON):

{
  "error": "Invalid API Key"
}

ข้อผิดพลาดที่พบบ่อย:

  • ลืมตั้งค่า Content-Type เป็น application/json ทำให้ Client ไม่สามารถ Parse Response ได้
  • ลืมตั้งค่า HTTP Status Code ให้ถูกต้อง
  • ไม่ Return จาก Middleware หลังจากส่ง Error Response ทำให้ Code ยังทำงานต่อไป
  • Hardcode API Key ใน Code
  • ไม่ใช้ HTTPS

สรุป

ในบทนี้ เราได้เรียนรู้วิธีการใช้ Middleware สำหรับ Authentication ใน API โดยเน้นไปที่การตรวจสอบ API Key และการให้สิทธิ์การเข้าถึง นอกจากนี้ เรายังได้เรียนรู้เกี่ยวกับการส่ง Error Response ที่ถูกต้อง และข้อผิดพลาดที่พบบ่อยในการ Implement Authentication ด้วย Middleware

ในบทถัดไป เราจะเรียนรู้เกี่ยวกับ CORS (Cross-Origin Resource Sharing) และวิธีการตั้งค่า CORS Headers ใน PHP เพื่อให้ API ของเราสามารถเข้าถึงได้จาก Domain อื่น

Office.in.th Custom Service

ต้องการพัฒนาระบบหรือปรับแต่งจากโครงสร้างนี้?

Office.in.th รับพัฒนาและออกแบบ Enterprise Web Application, API Integration และระบบบริหารงานภาครัฐ/เอกชน พร้อมการสนับสนุนระยะยาว

ดูบริการรับพัฒนาซอฟต์แวร์