จัดการผู้ใช้ บทบาท และสิทธิ์
ภาพรวม
ฟีเจอร์นี้ประกอบด้วยสองส่วนที่ทำงานร่วมกัน
- การจัดการผู้ใช้ ที่
/user-management— สร้าง แก้ไข ดูรายละเอียด และลบผู้ใช้ กำหนดบทบาท เปิดปิดสถานะ ระบุว่าผู้ใช้เข้าถึง LINE OA ใดได้บ้าง และสั่งรีเซ็ตรหัสผ่านแทนผู้ใช้ - ระบบสิทธิ์ — กลไกที่แปลงสิทธิ์ซึ่งเซิร์ฟเวอร์ส่งมา ให้กลายเป็นกฎที่หน้าเว็บใช้ควบคุมการเข้าถึงหน้า เมนู และปุ่มบางจุด
ผู้ใช้ในระบบนี้เป็นข้อมูลระดับองค์กร ไม่ได้ผูกกับ channel ใด channel หนึ่ง หน้านี้จึงถูกจัดเป็นหน้าระดับบัญชีเช่นเดียวกับหน้าจัดการ LINE OA และแสดงผลใน layout ที่ไม่มีเมนูด้านข้าง
จุดที่ควรทราบคือหน้านี้ ไม่ปรากฏในเมนูด้านข้าง ผู้ใช้เข้าถึงได้สองทางเท่านั้น คือปุ่มบนส่วนหัวของหน้าจัดการ LINE OA และเมนูลัด (quick access) โดยทั้งสองทางถูกกรองด้วยสิทธิ์การดูข้อมูลผู้ใช้ ตัวหน้าเองก็มีการตรวจสิทธิ์ระดับ route ครอบไว้อีกชั้นทั้งหน้ารายการและหน้าฟอร์ม
Business Flow
1. รายการผู้ใช้
- เมื่อเปิดหน้า ระบบตรวจสิทธิ์การดูข้อมูลผู้ใช้ก่อน แล้วตั้งค่า breadcrumb และเมนูที่กำลังใช้งาน
- ระบบโหลดเงื่อนไขการค้นหาล่าสุดจาก sessionStorage แล้วดึงข้อมูลจาก
GET /user - แถบเครื่องมือประกอบด้วยช่องค้นหา ตัวกรองสถานะ และตัวเลขจำนวนผู้ใช้ทั้งหมด
- ตารางแสดง 5 คอลัมน์ ได้แก่ ลำดับ ข้อมูลผู้ใช้ (รูปย่อ ชื่อเต็มที่คลิกเข้าดูรายละเอียดได้ และอีเมล) บทบาท สถานะ และปุ่มดำเนินการ
- ป้ายบทบาทถูกกำหนดสีอัตโนมัติจากชื่อบทบาท เช่น กลุ่มผู้ดูแลระบบเป็นสีแดง ผู้จัดการเป็นสีส้ม และผู้แก้ไขเป็นสีฟ้า
- คอลัมน์ดำเนินการมี 4 ปุ่ม คือ แก้ไข กำหนดสิทธิ์เข้าถึง OA รีเซ็ตรหัสผ่าน และลบ
- ทุกครั้งที่เปลี่ยนหน้า จำนวนต่อหน้า หรือเงื่อนไขการค้นหา ระบบจะบันทึกลง sessionStorage
- ปุ่มสร้างผู้ใช้อยู่ที่ส่วนหัวของหน้า
2. สร้าง แก้ไข และดูข้อมูลผู้ใช้
- หน้าฟอร์มรองรับสามโหมด คือ สร้างใหม่ แก้ไข และดูอย่างเดียว โดยแยกจากพารามิเตอร์ใน URL
- ระบบโหลดรายการบทบาทสำหรับ dropdown และโหลดข้อมูลผู้ใช้ในกรณีที่มีรหัสผู้ใช้
- ฟอร์มมี 5 ฟิลด์ ได้แก่ ชื่อ นามสกุล อีเมล บทบาท และสถานะ (ใช้งาน / ปิดใช้งาน)
- ในโหมดแก้ไข อีเมลและบทบาทถูกล็อกไว้ ไม่สามารถเปลี่ยนได้ ส่วนโหมดดูอย่างเดียวจะปิดทุกฟิลด์และแสดงเพียงปุ่มย้อนกลับ
- เมื่อบันทึก ระบบส่งข้อมูลไปยัง
POST /userสำหรับการสร้าง หรือPUT /user/{id}สำหรับการแก้ไข - เมื่อสำเร็จจะแสดงข้อความยืนยันและกลับไปหน้ารายการ หากเซิร์ฟเวอร์ระบุฟิลด์ที่ผิดพลาด ระบบจะแสดงข้อความรายฟิลด์ มิฉะนั้นจะเปิด modal แจ้งข้อผิดพลาด
3. ลบผู้ใช้
ปุ่มลบในตารางเปิดกล่องยืนยันแบบ inline เมื่อยืนยันแล้วระบบเรียก DELETE /user/{id} และโหลดตารางใหม่
4. รีเซ็ตรหัสผ่านแทนผู้ใช้
ปุ่มรูปกุญแจเปิดกล่องยืนยัน เมื่อยืนยันแล้วระบบเรียก POST /user/{id}/admin-reset-password จากนั้นเซิร์ฟเวอร์จะส่งอีเมลลิงก์ตั้งรหัสผ่านใหม่ให้ผู้ใช้รายนั้น รายละเอียดของขั้นตอนต่อจากนั้นอยู่ในหัวข้อจัดการรหัสผ่าน
5. กำหนดสิทธิ์เข้าถึง LINE OA ของผู้ใช้
- ปุ่มกำหนดสิทธิ์ในตารางเปิด modal ที่ดึงข้อมูลจาก
GET /user/{id}/oa-access - ระบบเลือกโหมดให้อัตโนมัติ หากผู้ใช้เคยถูกกำหนด OA เจาะจงไว้จะเริ่มที่โหมด "เฉพาะบาง OA" มิฉะนั้นจะเป็นโหมด "ทุก OA"
- ในโหมดเฉพาะบาง OA ระบบแสดงรายชื่อ channel ทั้งหมดให้ติ๊กเลือก
- หากเลือกโหมดเฉพาะบาง OA แต่ไม่ได้ติ๊กเลย ระบบจะแจ้งเตือนและไม่บันทึก
- เมื่อบันทึก ระบบส่งรายการ OA ไปยัง
PUT /user/{id}/oa-accessโดยการส่งรายการว่างมีความหมายว่า เข้าถึงได้ทุก channel - มุมกลับของการตั้งค่านี้คือ modal จัดการสิทธิ์เข้าถึงในหน้าจัดการ LINE OA ซึ่งมองจากฝั่ง channel
6. การแปลงสิทธิ์จากเซิร์ฟเวอร์มาเป็นกฎฝั่งหน้าเว็บ
- เซิร์ฟเวอร์ส่งสิทธิ์มาเป็นรายการของโมดูลพร้อมชุดการกระทำที่อนุญาต เช่น อ่าน สร้าง แก้ไข ลบ และส่งออก
- ระบบแปลงข้อมูลนี้ในสามขั้น
- ค้นหาว่าชื่อโมดูลฝั่งเซิร์ฟเวอร์ตรงกับหน้าใดในหน้าเว็บ โมดูลที่ไม่มีหน้ารองรับจะถูกข้ามไป
- แปลงชุดการกระทำ โดยการกระทำกลุ่มอ่านจะถูกแปลงเป็นสิทธิ์ "ดู" และการส่งออกจะถูกแปลงเป็นสิทธิ์ "ส่งออก" ส่วนสร้าง แก้ไข และลบ ไม่ถูกแปลง เข้าสู่ระบบสิทธิ์ฝั่งหน้าเว็บ
- โมดูลหนึ่งของเซิร์ฟเวอร์อาจปลดล็อกหลายหน้าในหน้าเว็บพร้อมกัน
- กฎที่ได้ถูกประกอบเป็นชุดกฎแบบอนุญาตล้วน ไม่มีการปฏิเสธเฉพาะเจาะจงและไม่มีเงื่อนไขระดับข้อมูล
- ชุดกฎถูกเก็บใน 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 สิทธิ์เข้าถึง OA
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 |
| รายการบทบาทสำหรับ dropdown | GET /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 ทำจริง
- บังคับให้อ่านได้เฉพาะของตัวเอง — รหัสผู้ใช้ใน path ต้องตรงกับผู้ใช้ที่ถือ token ถ้าไม่ตรงจะถูกปฏิเสธด้วยข้อความว่าเข้าถึงรหัสผู้ใช้อื่นไม่ได้ ดังนั้นหน้าเว็บจึงเรียกดูสิทธิ์ของคนอื่นไม่ได้เลย
- โหลด baseline ของผู้ใช้จากสิทธิ์ที่ผูกกับบทบาท แล้วดึงรายชื่อโมดูลทั้งหมดในระบบมาประกอบ
- ตัดสินด้วยประเภทของผู้ใช้ — ถ้าเป็นผู้ใช้ประเภทลูกค้าและองค์กรนั้นมีการตั้งค่าโมดูลระดับองค์กรไว้ จะใช้ค่าที่ผู้ดูแลแพลตฟอร์มกำหนดแทน baseline ของบทบาท แต่ถ้าเป็นผู้ใช้ประเภทผู้ดำเนินการแพลตฟอร์ม (รวมบทบาทรหัส 1) จะใช้ baseline ตามบทบาทเสมอ ไม่ถูก override
- ตอบกลับเป็นรายการที่จับคู่ชื่อโมดูลกับชุดการกระทำ ให้หน้าเว็บนำไปแปลงเป็นชุดกฎ
ผลที่ตามมาคือ ผู้ใช้สองคนที่มีบทบาทเดียวกันแต่คนละองค์กร อาจเห็นเมนูไม่เท่ากัน ถ้าองค์กรถูกตั้งค่าโมดูลต่างกัน
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 ตรวจโดยตรง สอดคล้องกับที่หน้าเว็บตรวจรหัสบทบาทเองแทนการผ่านระบบสิทธิ์กลาง