Skip to main content

จัดการผู้ใช้ บทบาท และสิทธิ์

ภาพรวม

ฟีเจอร์นี้ประกอบด้วยสองส่วนที่ทำงานร่วมกัน

  • การจัดการผู้ใช้ ที่ /user-management — สร้าง แก้ไข ดูรายละเอียด และลบผู้ใช้ กำหนดบทบาท เปิดปิดสถานะ ระบุว่าผู้ใช้เข้าถึง LINE OA ใดได้บ้าง และสั่งรีเซ็ตรหัสผ่านแทนผู้ใช้
  • ระบบสิทธิ์ — กลไกที่แปลงสิทธิ์ซึ่งเซิร์ฟเวอร์ส่งมา ให้กลายเป็นกฎที่หน้าเว็บใช้ควบคุมการเข้าถึงหน้า เมนู และปุ่มบางจุด

ผู้ใช้ในระบบนี้เป็นข้อมูลระดับองค์กร ไม่ได้ผูกกับ channel ใด channel หนึ่ง หน้านี้จึงถูกจัดเป็นหน้าระดับบัญชีเช่นเดียวกับหน้าจัดการ LINE OA และแสดงผลใน layout ที่ไม่มีเมนูด้านข้าง

จุดที่ควรทราบคือหน้านี้ ไม่ปรากฏในเมนูด้านข้าง ผู้ใช้เข้าถึงได้สองทางเท่านั้น คือปุ่มบนส่วนหัวของหน้าจัดการ LINE OA และเมนูลัด (quick access) โดยทั้งสองทางถูกกรองด้วยสิทธิ์การดูข้อมูลผู้ใช้ ตัวหน้าเองก็มีการตรวจสิทธิ์ระดับ route ครอบไว้อีกชั้นทั้งหน้ารายการและหน้าฟอร์ม

Business Flow

1. รายการผู้ใช้

  1. เมื่อเปิดหน้า ระบบตรวจสิทธิ์การดูข้อมูลผู้ใช้ก่อน แล้วตั้งค่า breadcrumb และเมนูที่กำลังใช้งาน
  2. ระบบโหลดเงื่อนไขการค้นหาล่าสุดจาก sessionStorage แล้วดึงข้อมูลจาก GET /user
  3. แถบเครื่องมือประกอบด้วยช่องค้นหา ตัวกรองสถานะ และตัวเลขจำนวนผู้ใช้ทั้งหมด
  4. ตารางแสดง 5 คอลัมน์ ได้แก่ ลำดับ ข้อมูลผู้ใช้ (รูปย่อ ชื่อเต็มที่คลิกเข้าดูรายละเอียดได้ และอีเมล) บทบาท สถานะ และปุ่มดำเนินการ
  5. ป้ายบทบาทถูกกำหนดสีอัตโนมัติจากชื่อบทบาท เช่น กลุ่มผู้ดูแลระบบเป็นสีแดง ผู้จัดการเป็นสีส้ม และผู้แก้ไขเป็นสีฟ้า
  6. คอลัมน์ดำเนินการมี 4 ปุ่ม คือ แก้ไข กำหนดสิทธิ์เข้าถึง OA รีเซ็ตรหัสผ่าน และลบ
  7. ทุกครั้งที่เปลี่ยนหน้า จำนวนต่อหน้า หรือเงื่อนไขการค้นหา ระบบจะบันทึกลง sessionStorage
  8. ปุ่มสร้างผู้ใช้อยู่ที่ส่วนหัวของหน้า

2. สร้าง แก้ไข และดูข้อมูลผู้ใช้

  1. หน้าฟอร์มรองรับสามโหมด คือ สร้างใหม่ แก้ไข และดูอย่างเดียว โดยแยกจากพารามิเตอร์ใน URL
  2. ระบบโหลดรายการบทบาทสำหรับ dropdown และโหลดข้อมูลผู้ใช้ในกรณีที่มีรหัสผู้ใช้
  3. ฟอร์มมี 5 ฟิลด์ ได้แก่ ชื่อ นามสกุล อีเมล บทบาท และสถานะ (ใช้งาน / ปิดใช้งาน)
  4. ในโหมดแก้ไข อีเมลและบทบาทถูกล็อกไว้ ไม่สามารถเปลี่ยนได้ ส่วนโหมดดูอย่างเดียวจะปิดทุกฟิลด์และแสดงเพียงปุ่มย้อนกลับ
  5. เมื่อบันทึก ระบบส่งข้อมูลไปยัง POST /user สำหรับการสร้าง หรือ PUT /user/{id} สำหรับการแก้ไข
  6. เมื่อสำเร็จจะแสดงข้อความยืนยันและกลับไปหน้ารายการ หากเซิร์ฟเวอร์ระบุฟิลด์ที่ผิดพลาด ระบบจะแสดงข้อความรายฟิลด์ มิฉะนั้นจะเปิด modal แจ้งข้อผิดพลาด

3. ลบผู้ใช้

ปุ่มลบในตารางเปิดกล่องยืนยันแบบ inline เมื่อยืนยันแล้วระบบเรียก DELETE /user/{id} และโหลดตารางใหม่

4. รีเซ็ตรหัสผ่านแทนผู้ใช้

ปุ่มรูปกุญแจเปิดกล่องยืนยัน เมื่อยืนยันแล้วระบบเรียก POST /user/{id}/admin-reset-password จากนั้นเซิร์ฟเวอร์จะส่งอีเมลลิงก์ตั้งรหัสผ่านใหม่ให้ผู้ใช้รายนั้น รายละเอียดของขั้นตอนต่อจากนั้นอยู่ในหัวข้อจัดการรหัสผ่าน

5. กำหนดสิทธิ์เข้าถึง LINE OA ของผู้ใช้

  1. ปุ่มกำหนดสิทธิ์ในตารางเปิด modal ที่ดึงข้อมูลจาก GET /user/{id}/oa-access
  2. ระบบเลือกโหมดให้อัตโนมัติ หากผู้ใช้เคยถูกกำหนด OA เจาะจงไว้จะเริ่มที่โหมด "เฉพาะบาง OA" มิฉะนั้นจะเป็นโหมด "ทุก OA"
  3. ในโหมดเฉพาะบาง OA ระบบแสดงรายชื่อ channel ทั้งหมดให้ติ๊กเลือก
  4. หากเลือกโหมดเฉพาะบาง OA แต่ไม่ได้ติ๊กเลย ระบบจะแจ้งเตือนและไม่บันทึก
  5. เมื่อบันทึก ระบบส่งรายการ OA ไปยัง PUT /user/{id}/oa-access โดยการส่งรายการว่างมีความหมายว่า เข้าถึงได้ทุก channel
  6. มุมกลับของการตั้งค่านี้คือ modal จัดการสิทธิ์เข้าถึงในหน้าจัดการ LINE OA ซึ่งมองจากฝั่ง channel

6. การแปลงสิทธิ์จากเซิร์ฟเวอร์มาเป็นกฎฝั่งหน้าเว็บ

  1. เซิร์ฟเวอร์ส่งสิทธิ์มาเป็นรายการของโมดูลพร้อมชุดการกระทำที่อนุญาต เช่น อ่าน สร้าง แก้ไข ลบ และส่งออก
  2. ระบบแปลงข้อมูลนี้ในสามขั้น
    • ค้นหาว่าชื่อโมดูลฝั่งเซิร์ฟเวอร์ตรงกับหน้าใดในหน้าเว็บ โมดูลที่ไม่มีหน้ารองรับจะถูกข้ามไป
    • แปลงชุดการกระทำ โดยการกระทำกลุ่มอ่านจะถูกแปลงเป็นสิทธิ์ "ดู" และการส่งออกจะถูกแปลงเป็นสิทธิ์ "ส่งออก" ส่วนสร้าง แก้ไข และลบ ไม่ถูกแปลง เข้าสู่ระบบสิทธิ์ฝั่งหน้าเว็บ
    • โมดูลหนึ่งของเซิร์ฟเวอร์อาจปลดล็อกหลายหน้าในหน้าเว็บพร้อมกัน
  3. กฎที่ได้ถูกประกอบเป็นชุดกฎแบบอนุญาตล้วน ไม่มีการปฏิเสธเฉพาะเจาะจงและไม่มีเงื่อนไขระดับข้อมูล
  4. ชุดกฎถูกเก็บใน state ส่วนกลางแต่ ไม่ถูก persist จึงต้องคำนวณใหม่ทุกครั้งที่โหลดหน้า จุดที่คำนวณมีสองแห่งคือตอนโหลดแอปพลิเคชัน และตอนเลือก channel เพื่อเข้าใช้งาน

ตารางการแปลงชื่อโมดูลของเซิร์ฟเวอร์ไปเป็นหน้าในหน้าเว็บ

โมดูลฝั่งเซิร์ฟเวอร์หน้าที่ถูกปลดล็อก
dashboardแดชบอร์ด
line-oaจัดการ LINE OA, เมนูบิลเดอร์ และกลุ่มหน้าจัดการเนื้อหาทั้งหมด
userจัดการผู้ใช้ และหน้าตั้งค่า
rich-menuริชเมนูทั้งสามประเภท (default, custom, switch)
rich-messageจัดการ Rich Message
template-messageจัดการ Template Message
campaignจัดการแคมเปญ และปฏิทินวางแผนแคมเปญ
auto-responseตอบกลับอัตโนมัติ และ Quick Reply
report-all-friendsรายงานเพื่อนทั้งหมด
audiencesจัดการกลุ่มเป้าหมายทุกรูปแบบ
form-builderตัวสร้างฟอร์ม และการตั้งค่า OTP
customer-databaseฐานข้อมูลสมาชิก
import-mappingการจับคู่ข้อมูลนำเข้า
attribute-masterการตั้งค่าแอตทริบิวต์
trigger-ruleกฎทริกเกอร์
workflowเวิร์กโฟลว์
friend-trackการติดตามเพื่อน
api-keyจัดการ API Key
system-attributeหน้าตั้งค่า
system_moduleฐานความรู้ และการซิงก์ BigQuery

7. การนำสิทธิ์ไปใช้กรองส่วนติดต่อผู้ใช้

  • ระดับหน้า — คอมโพเนนต์ครอบหน้า (PermissionGuard) จะไม่แสดงอะไรเลยระหว่างที่สิทธิ์ยังโหลดไม่เสร็จ แสดงหน้าแจ้งไม่มีสิทธิ์เมื่อไม่ผ่านเงื่อนไข และแสดงเนื้อหาจริงเมื่อผ่าน
  • เมนูด้านข้าง — แต่ละรายการเมนูถูกเพิ่มเข้าไปก็ต่อเมื่อผู้ใช้มีสิทธิ์ดูหน้านั้น เมนูริชเมนูจะตรวจสิทธิ์รวมของทั้งสามประเภทก่อน แล้วจึงกรองเมนูย่อยแต่ละตัว ส่วนกลุ่มเมนู Apps และ Settings ถูกแสดงโดยไม่ตรวจสิทธิ์ ยกเว้นเมนูย่อยการตั้งค่า OTP
  • เมนูลัด — รายการที่ไม่ระบุหน้าอ้างอิงจะแสดงเสมอ ส่วนรายการที่ระบุจะถูกกรองด้วยสิทธิ์เช่นเดียวกับเมนูด้านข้าง
  • ระดับปุ่ม — มีการใช้กรองปุ่มเพียงไม่กี่จุด เช่น ปุ่มเข้าหน้าจัดการผู้ใช้บนหน้าจัดการ LINE OA
  • ข้อจำกัดที่ควรทราบ — เนื่องจากการกระทำสร้าง แก้ไข และลบไม่ถูกแปลงเข้าสู่ระบบสิทธิ์ฝั่งหน้าเว็บ ปุ่มเหล่านี้จึงแสดงกับทุกคนที่เข้าถึงหน้านั้นได้ การควบคุมที่แท้จริงจึงอยู่ที่ฝั่งเซิร์ฟเวอร์
  • สิทธิ์ super admin — การจัดการสิทธิ์เข้าถึง channel รายผู้ใช้ในหน้าจัดการ LINE OA ตรวจจากรหัสบทบาทโดยตรง ไม่ได้ผ่านระบบสิทธิ์กลาง

หน้าจอและองค์ประกอบหลัก

หน้ารายการผู้ใช้

ตรรกะทั้งหมดของหน้ารายการรวมอยู่ในตัวควบคุมเดียว (src/components/user-management/list/user-management.container.tsx) ซึ่งสร้างทั้งตาราง แถบเครื่องมือ และคอลัมน์ขึ้นเองภายในไฟล์ พร้อมจัดการการลบ การรีเซ็ตรหัสผ่าน และการค้นหา

Modal นี้ใช้ตัวเลือกสองโหมดคู่กับรายการติ๊กเลือก ทำให้ผู้ดูแลระบบเลือกได้ระหว่างการเปิดให้เข้าถึงทุก channel กับการระบุ channel เจาะจง

หน้าฟอร์มผู้ใช้

หน้าฟอร์มแยกเป็นตัวควบคุมที่ดูแลการดึงข้อมูลบทบาท การประกอบข้อมูลส่งเซิร์ฟเวอร์ และการบันทึก กับคอมโพเนนต์ฟอร์มที่ดูแลการแสดงผลและการเปิดปิดฟิลด์ตามโหมดการใช้งาน

ชั้นระบบสิทธิ์

ระบบสิทธิ์อยู่ในโฟลเดอร์ src/components/ability/ แยกเป็นสองไฟล์หลัก คือไฟล์ตารางการแปลงชื่อโมดูลกับฟังก์ชันแปลงข้อมูล และไฟล์ที่ประกอบกฎขึ้นเป็นชุดสิทธิ์ที่ใช้งานได้จริง

ปลายทาง API หลัก

การทำงานปลายทาง
รายการผู้ใช้GET /user
ข้อมูลผู้ใช้รายคนGET /user/{id}
สร้างผู้ใช้POST /user
แก้ไขผู้ใช้PUT /user/{id}
ลบผู้ใช้DELETE /user/{id}
สิทธิ์เข้าถึง OA ของผู้ใช้GET และ PUT /user/{id}/oa-access
รีเซ็ตรหัสผ่านโดยผู้ดูแลระบบPOST /user/{id}/admin-reset-password
โหลดสิทธิ์เพื่อสร้างชุดกฎGET /user/{id}/permission
รายการบทบาทสำหรับ dropdownGET /system-role/find-all-object

จุดเชื่อมต่อกับฟีเจอร์อื่น

  • เข้าสู่ระบบ — ชุดกฎสิทธิ์ถูกสร้างขึ้นตอนโหลดแอปพลิเคชันและตอนเลือก channel รวมถึงการเปิดสิทธิ์เข้าหน้าเลือก OA ไว้ก่อนเสมอ
  • จัดการ LINE OA — เป็นทางเข้าหลักของหน้านี้ และมี modal จัดการสิทธิ์เข้าถึงที่เป็นมุมกลับของการตั้งค่า OA access
  • จัดการรหัสผ่าน — ปุ่มรีเซ็ตรหัสผ่านในตารางเป็นจุดเริ่มต้นของเส้นทางส่งลิงก์ตั้งรหัสผ่านใหม่ให้ผู้ใช้
  • การกำหนดสิทธิ์ของบทบาท — CMS นี้ไม่มีหน้าจัดการบทบาทและสิทธิ์ การกำหนดว่าบทบาทใดเข้าถึงโมดูลใดได้ทำที่ฝั่งเซิร์ฟเวอร์
  • ทุกหน้าในระบบ — ระบบสิทธิ์ที่อธิบายในหน้านี้เป็นตัวกำหนดว่าผู้ใช้แต่ละคนจะเห็นเมนูและเข้าถึงหน้าใดได้บ้าง

รายละเอียดฝั่ง Backend (CMS API)

หัวข้อนี้สำคัญเป็นพิเศษ เพราะระบบสิทธิ์ฝั่ง backend ไม่ได้ทำงานอย่างที่ชื่อบอก และการเข้าใจผิดตรงนี้นำไปสู่การประเมินความปลอดภัยที่คลาดเคลื่อนได้ง่าย

ระบบสิทธิ์มี 4 ชั้น และบังคับใช้จริงเพียง 3 ชั้น

ชั้นบังคับใช้จริงหรือไม่ทำอะไร
CASL policy (สิทธิ์ระดับ action/module)ไม่บังคับมีข้อมูลกำกับครบทุกเส้นทาง แต่ตัวตรวจสอบถูกทำให้ปล่อยผ่านทุกคำขอ
SuperAdminGuardบังคับจริงต้องมีรหัสบทบาทเท่ากับ 1
ModuleGateบังคับจริงถ้าผู้ดูแลระดับแพลตฟอร์มปิดโมดูลของ organization ไว้ ลูกค้าจะได้ 403 แม้ยิง API ตรง
AppEnabledGuardบังคับจริงapp (นัดหมาย / loyalty / bulletin) ต้องถูกเปิดให้องค์กรนั้นก่อน

ข้อสรุปที่ต้องจำ: สิทธิ์ในตารางบทบาทและโมดูลถูกใช้เพียงเพื่อซ่อน/แสดงเมนูใน cms-web เท่านั้น ไม่ได้ปิดกั้นการเรียก API — พฤติกรรมนี้ถูกยกมาจากระบบเวอร์ชันก่อนหน้าโดยตั้งใจ (ตัวตรวจ policy เดิมก็คืนค่าอนุญาตตลอดเช่นกัน) ข้อสังเกตในหน้านี้ที่ว่า "การควบคุมที่แท้จริงอยู่ที่ฝั่งเซิร์ฟเวอร์" จึงต้องเข้าใจให้ตรงว่าหมายถึง ModuleGate และ SuperAdminGuard ไม่ใช่สิทธิ์รายการกระทำ

สิ่งที่ GET /api/user/:id/permission ทำจริง

  1. บังคับให้อ่านได้เฉพาะของตัวเอง — รหัสผู้ใช้ใน path ต้องตรงกับผู้ใช้ที่ถือ token ถ้าไม่ตรงจะถูกปฏิเสธด้วยข้อความว่าเข้าถึงรหัสผู้ใช้อื่นไม่ได้ ดังนั้นหน้าเว็บจึงเรียกดูสิทธิ์ของคนอื่นไม่ได้เลย
  2. โหลด baseline ของผู้ใช้จากสิทธิ์ที่ผูกกับบทบาท แล้วดึงรายชื่อโมดูลทั้งหมดในระบบมาประกอบ
  3. ตัดสินด้วยประเภทของผู้ใช้ — ถ้าเป็นผู้ใช้ประเภทลูกค้าและองค์กรนั้นมีการตั้งค่าโมดูลระดับองค์กรไว้ จะใช้ค่าที่ผู้ดูแลแพลตฟอร์มกำหนดแทน baseline ของบทบาท แต่ถ้าเป็นผู้ใช้ประเภทผู้ดำเนินการแพลตฟอร์ม (รวมบทบาทรหัส 1) จะใช้ baseline ตามบทบาทเสมอ ไม่ถูก override
  4. ตอบกลับเป็นรายการที่จับคู่ชื่อโมดูลกับชุดการกระทำ ให้หน้าเว็บนำไปแปลงเป็นชุดกฎ

ผลที่ตามมาคือ ผู้ใช้สองคนที่มีบทบาทเดียวกันแต่คนละองค์กร อาจเห็นเมนูไม่เท่ากัน ถ้าองค์กรถูกตั้งค่าโมดูลต่างกัน

ModuleGate — ชั้นที่ปิดกั้นจริงที่ระดับ API

Gate นี้ทำงานตามลำดับ: อ่านประเภทของผู้เรียกจาก context → ถ้าเป็นผู้ดำเนินการแพลตฟอร์ม (หรือระบุตัวไม่ได้) จะปล่อยผ่านทันที → ถ้าเป็นลูกค้าจึงตรวจว่าโมดูลนั้นเปิดให้องค์กรหรือไม่ ด้วยตรรกะ baseline-กับ-override ชุดเดียวกับข้างบน

จุดที่ควรรู้เรื่องพฤติกรรมเมื่อเกิดข้อผิดพลาด:

  • ModuleGate ออกแบบให้ fail open — ถ้าการตรวจสอบล้มเหลว (เช่น query สะดุด) ระบบจะปล่อยผ่านพร้อมบันทึก log แทนที่จะปฏิเสธ เพื่อไม่ให้ทั้งองค์กรถูกล็อกออกจากระบบเพราะปัญหาชั่วคราว
  • ตรงข้ามกับเส้นทางเฉพาะแพลตฟอร์มที่ fail closed — เส้นทางเปิด/ปิด app ให้องค์กรจะปฏิเสธไว้ก่อนเมื่อตรวจไม่ได้ เพราะความเสี่ยงคือการยกระดับสิทธิ์

โมดูลที่ถูกครอบด้วย ModuleGate ได้แก่ api-key, attribute-master, audiences, auto-response, campaign, customer-database, form-builder, friend-track, import-mapping, report-all-friends, rich-menu, rich-message, template-message, trigger-rule และ workflow

รายละเอียดของโมดูล user

  • ทุกเส้นทางใช้ guard แบบยอมรับ token ที่ยังไม่มีรหัส OA ไม่ใช่ guard ปกติ เพราะหน้าจัดการผู้ใช้เป็นหน้าระดับบัญชีที่ต้องเข้าถึงได้โดยไม่ต้องเลือก channel ก่อน
  • รายการผู้ใช้ถูกจำกัดขอบเขตตามองค์กรของผู้เรียกเสมอ ผู้ดูแลขององค์กรหนึ่งจึงไม่เห็นผู้ใช้ขององค์กรอื่นแม้ชั้น policy จะไม่บังคับ
  • การสร้างผู้ใช้รับข้อมูลแบบ multipart เพื่อรองรับการอัปโหลดรูปโปรไฟล์ พร้อมเข้ารหัสรหัสผ่านและบันทึกลงประวัติรหัสผ่านไปในคำขอเดียว
  • การลบเป็น soft delete โดยประทับเวลาที่ลบไว้ ส่วนการลบจริงมีเส้นทางแยกที่ต้องเป็น super admin และต้องส่งพารามิเตอร์ยืนยัน — หน้าเว็บไม่มีปุ่มเรียกเส้นทางนี้
  • สิทธิ์เข้าถึง OA รายคน เขียนลงตารางเดียวกับ modal ในหน้าจัดการ LINE OA จึงเป็นข้อมูลชุดเดียวกันที่มองจากคนละมุมจริง ๆ ฟีเจอร์นี้เป็นของใหม่ที่ไม่มีในระบบเวอร์ชันก่อนหน้า
  • GET /api/user/find-all-object ที่ใช้ทำ dropdown ไม่มีข้อมูลกำกับสิทธิ์เลย ตามที่ระบบเดิมเคยคอมเมนต์ไว้

รายละเอียดของบทบาท (System Role)

  • โมดูลบทบาทฝั่ง backend เปิดเพียง endpoint เดียว คือ GET /api/system-role/find-all-object สำหรับทำ dropdown เท่านั้น
  • ไม่มี API สำหรับแก้ไขบทบาทหรือสิทธิ์ของบทบาท — ข้อมูลเหล่านี้เป็นข้อมูล master ที่ตั้งไว้ในฐานข้อมูลโดยตรง แล้วปรับต่อรายองค์กรผ่านการตั้งค่าโมดูลของ organization นี่คือคำอธิบายเชิงเทคนิคของข้อสังเกตที่ว่า CMS ไม่มีหน้าจัดการบทบาท
  • บทบาทรหัส 1 คือ super admin ซึ่งเป็นค่าที่ guard ระดับ super admin ตรวจโดยตรง สอดคล้องกับที่หน้าเว็บตรวจรหัสบทบาทเองแทนการผ่านระบบสิทธิ์กลาง