Skip to main content

API Key สำหรับระบบภายนอก

ภาพรวม

API Key ใช้ให้ระบบภายนอกของลูกค้า เช่น POS, CRM หรือเว็บไซต์ของลูกค้าเอง สามารถเรียกเข้ามาที่ client-api ได้โดยไม่ต้องใช้ JWT ของผู้ใช้ CMS โมดูลนี้คือหน้าจัดการ key ครอบคลุมการสร้าง แก้ไขชื่อ เปิดหรือปิดสถานะ และลบ

route ทั้งหมดอยู่บน group public ร่วมกับ JwtLoginAuth และ ModuleGate("api-key") กล่าวคือผู้เรียกยังต้องมี token ที่ล็อกอินแล้ว แต่ไม่บังคับว่าต้องเลือก LINE OA ก่อน

คำเตือนสำคัญ: โมดูลนี้ถูก port มาแบบหนึ่งต่อหนึ่ง พร้อมกับ bug ของโค้ด TypeScript หลายจุด ซึ่งมีคอมเมนต์กำกับไว้ในโค้ดว่าไม่ให้แก้ ผู้ที่จะเข้ามา debug ควรทราบพฤติกรรมเหล่านี้ก่อน

Business Flow

  1. GET /api/api-key แสดงรายการ key ของ OA ปัจจุบัน แบบแบ่งหน้าในรูปแบบ {data, total}
  2. POST /api/api-key สร้าง key ใหม่
  3. GET /api/api-key/:id ดูรายละเอียดของ key
  4. PUT /api/api-key/:id แก้ไขข้อมูล และ PUT /api/api-key/:id/status เปิดหรือปิดการใช้งาน
  5. DELETE /api/api-key/:id ลบ key
  6. ระบบภายนอกนำค่า key ไปแนบใน request ที่ยิงไปยัง client-api ซึ่ง client-api จะตรวจสอบกับตาราง api_key

พฤติกรรมและ bug ที่คงไว้ตามโค้ดเดิม

รายละเอียดเหล่านี้ระบุไว้ใน service.go

  • POST ที่ไม่ส่งฟิลด์ key มาใน body จะทำให้ INSERT ขาดคอลัมน์ key ซึ่งเป็น NOT NULL เกิด Postgres error และตอบ 500 พร้อม APP_000 — สร้างสำเร็จได้เฉพาะกรณีที่ client ส่ง key มาเอง
  • findAll ค้นหาด้วยคอลัมน์ api_key.name และ api_key.keywords ซึ่ง ไม่มีอยู่จริงในตาราง (ถูก copy มาจากโมดูล auto-response) ดังนั้นการส่ง ?search= ที่ไม่ว่าง หรือ ?orderBy=name จะทำให้เกิด 500
  • หากไม่ส่ง ?lineOaId มา SQL จะกลายเป็น line_oa_id = NULL และคืนผลลัพธ์เป็น {"data":[],"total":0}
  • การส่ง ?status= หลายค่าจะทำให้เกิดการเทียบ array literal กับคอลัมน์ enum และตอบ 500
  • update() ตรวจสอบชื่อซ้ำแล้วไม่ได้ใช้ผลลัพธ์ (คงไว้เพื่อ parity) และหาก body มี property ที่ไม่ตรงกับคอลัมน์ใดจะตอบ 500
  • updateStatus() ไม่ ล้าง cache ของ find-all

ไฟล์และฟังก์ชันหลัก

โค้ดอยู่ที่ internal/modules/apikey/ ประกอบด้วย controller.go, service.go และ dto.go

MethodRouteHandlerGuard
GET/api/api-keyct.findAllJwtLogin + ModuleGate
GET/api/api-key/:idct.findByIdJwtLogin + ModuleGate
POST/api/api-keyct.createJwtLogin + ModuleGate
PUT/api/api-key/:idct.updateJwtLogin + ModuleGate
PUT/api/api-key/:id/statusct.updateStatusJwtLogin + ModuleGate
DELETE/api/api-key/:idct.deleteByIdJwtLogin + ModuleGate

ลำดับ middleware คือ jwtLogin แล้วตามด้วย gate ก่อนถึง handler เหตุผลคือ guard ต้องรันก่อนเพื่อเติมค่า selfId และ organizationId ลงใน CLS ให้ gate นำไป resolve ได้ หากค่าเหล่านี้ไม่ถูกเติม gate จะ fail open

จุดเชื่อมต่อกับ Service อื่น

  • Permission — ต้องผ่าน JwtLoginAuth และ ModuleGate(d, "api-key") ลูกค้าที่ organization ปิดโมดูล api-key ไว้จะได้ 403 ส่วนผู้ใช้ประเภท onemoby จะ bypass ทั้งนี้ PolicyModuleApiKey มีอยู่ใน enum แต่ไม่ได้ถูกนำมา annotate route ชุดนี้
  • ตารางapi_key
  • Redis — cache ผลลัพธ์ของ find-all (มี bug ที่ updateStatus ไม่ invalidate cache)
  • ผู้บริโภค key — line-management-client-api-go ซึ่งเป็นคนละ service
  • โมดูลข้างเคียงที่ไม่มี route — ทะเบียน API Client