ระบบจัดการสิทธิ์คืออะไรและทำไมต้องมี
เวลาเราทำเว็บที่มีหลายคนใช้งาน เช่น มีแอดมิน (ผู้ดูแลระบบ) กับสมาชิกทั่วไป เราต้องกำหนดว่าใครทำอะไรได้บ้าง นี่คือสิ่งที่เรียกว่า Authorization (การตรวจสอบสิทธิ์การเข้าถึง) ถ้าไม่มีระบบนี้ สมาชิกทั่วไปอาจจะกดเข้าไปลบข้อมูลของคนอื่นได้ ซึ่งเป็นเรื่องใหญ่มากในการทำโปรแกรม
ปกติเราจะใช้ระบบที่เรียกว่า Role (บทบาท) เช่น กำหนดให้คนนี้เป็น "บรรณาธิการ" แล้วให้สิทธิ์ "แก้ไขบทความ" กับคนที่เป็นบรรณาธิการทุกคน วิธีนี้ง่ายและใช้ได้ดีกับงานส่วนใหญ่ แต่พอโปรเจกต์เริ่มโตขึ้น ความต้องการจะซับซ้อนขึ้นจนระบบแบบเดิมเอาไม่อยู่
วันนี้เราจะมาดูสองตัวช่วยยอดนิยมในโลกของ Laravel (เฟรมเวิร์กสำหรับเขียนเว็บด้วยภาษา PHP) คือ Spatie Permission และ Bouncer ทั้งคู่ช่วยให้เราจัดการสิทธิ์ได้ง่ายขึ้น แต่มีจุดตัดสินใจสำคัญเพียงข้อเดียวที่ทำให้คุณเลือกตัวที่ใช่สำหรับงานของคุณได้ทันที
คำถามตัดสินใจ: สิทธิ์ของคุณผูกกับ "ประเภท" หรือ "ชิ้นงาน"
ก่อนจะลงมือเขียนโค้ด ให้คุณถามตัวเองว่าสิทธิ์ที่คุณต้องการนั้นเป็นแบบไหน ถ้าคุณต้องการแค่บอกว่า "บรรณาธิการแก้ไขบทความได้" นี่คือการจัดการสิทธิ์ตาม ชนิดของงาน ซึ่งหมายความว่าบรรณาธิการทุกคนแก้ไขบทความได้ทุกชิ้นในฐานข้อมูล
แต่ถ้าวันหนึ่งลูกค้าบอกว่า "ให้คุณสมชายแก้ไขได้แค่บทความที่เขาเขียนเองเท่านั้น" สถานการณ์จะเปลี่ยนไปทันที นี่คือการจัดการสิทธิ์ที่ผูกกับ ชิ้นงานเฉพาะเจาะจง (เช่น บทความหมายเลข 4182) ซึ่งแต่ละแพ็กเกจมีวิธีรับมือเรื่องนี้ต่างกันอย่างชัดเจน
การเลือกให้ถูกตั้งแต่แรกจะช่วยประหยัดเวลาคุณได้มหาศาล เพราะถ้าเลือกผิด คุณอาจต้องมานั่งรื้อโค้ดเขียนระบบจัดการสิทธิ์ใหม่ทั้งหมดในวันที่โปรเจกต์ใกล้เสร็จ ดังนั้นลองดูความแตกต่างของทั้งสองตัวนี้กันครับ
Spatie Permission: ทางเลือกยอดนิยมสำหรับสิทธิ์แบบทั่วไป
Spatie Permission เป็นแพ็กเกจที่ได้รับความนิยมสูงที่สุดในโลกของ Laravel เพราะมันใช้งานง่ายและตรงไปตรงมา สิทธิ์ของมันจะอยู่ในรูปของ "ชื่อ" ที่เก็บไว้ในฐานข้อมูล เช่น edit articles (แก้ไขบทความ) ซึ่งเหมาะมากกับระบบที่สิทธิ์ไม่ผูกติดกับข้อมูลรายแถว
การติดตั้งทำได้ง่ายโดยการเพิ่ม Trait (ชุดคำสั่งที่นำมาใช้ซ้ำได้) เข้าไปในโมเดล User จากนั้นคุณก็สามารถสร้างบทบาทและกำหนดสิทธิ์ได้ทันทีผ่านคำสั่งที่อ่านแล้วเข้าใจง่ายเหมือนภาษาอังกฤษทั่วไป
ข้อดีที่สุดของตัวนี้คือ Community (สังคมผู้ใช้งาน) ที่ใหญ่มาก หากคุณติดปัญหาอะไร แค่ค้นหาใน Google หรือถาม AI ก็จะมีคำตอบรออยู่เสมอ เพราะแทบทุกคนที่เขียน Laravel เคยผ่านการใช้แพ็กเกจตัวนี้มาแล้วทั้งสิ้น
// สร้างบทบาทใหม่
$editor = Role::create(['name' => 'editor']);
// ให้สิทธิ์แก้ไขบทความกับบทบาทนี้
$editor->givePermissionTo(Permission::create(['name' => 'edit articles']));
// มอบบทบาทให้ผู้ใช้งาน
$user->assignRole('editor');
// ตรวจสอบสิทธิ์
if ($user->can('edit articles')) {
// โค้ดสำหรับแสดงปุ่มแก้ไข
}
อธิบายโค้ด: บรรทัดแรกสร้างชื่อกลุ่มผู้ใช้งาน บรรทัดที่สองสร้างชื่อสิทธิ์และผูกเข้ากับกลุ่ม บรรทัดที่สามคือการระบุว่าใครเป็นบรรณาธิการ และบรรทัดสุดท้ายคือการเช็คว่าผู้ใช้คนนี้มีสิทธิ์แก้ไขหรือไม่
ผลลัพธ์: ถ้าผู้ใช้มีสิทธิ์ edit articles โปรแกรมจะคืนค่าเป็น true และเข้าทำงานในบล็อก if ได้สำเร็จ
Bouncer: เมื่อสิทธิ์ต้องผูกกับข้อมูลรายแถว
Bouncer ถูกสร้างมาเพื่อแก้ปัญหาเรื่องการจัดการสิทธิ์ที่ซับซ้อนขึ้น โดยเฉพาะการอนุญาตให้คนทำอะไรบางอย่างกับ "ข้อมูลเฉพาะชิ้น" ได้ เช่น การอนุญาตให้คนเขียนบทความแก้ไขได้แค่บทความของตัวเองเท่านั้น โดยไม่ต้องเขียนโค้ดเช็คเงื่อนไขเองให้ยุ่งยาก
จุดเด่นที่ทำให้ Bouncer ต่างออกไปคือมันรองรับการ "ห้าม" (Forbid) สิทธิ์ได้โดยตรง ซึ่งมีประโยชน์มากในกรณีที่คุณต้องการระงับการใช้งานของใครบางคนชั่วคราว โดยไม่ต้องไปลบสิทธิ์หรือลบบทบาทของเขาออกให้เสียเวลา เพียงแค่สั่งห้ามไว้ ทุกอย่างก็จบ
แม้ Bouncer จะมีคนใช้น้อยกว่า Spatie แต่ความสามารถในการจัดการสิทธิ์ระดับแถวข้อมูลนั้นทรงพลังมาก ถ้างานของคุณต้องมีการจัดการสิทธิ์ที่เปลี่ยนไปมาตามข้อมูลในฐานข้อมูล Bouncer คือเครื่องมือที่ช่วยลดโค้ดในส่วน Policy (กฎการเข้าถึงข้อมูล) ของคุณได้เยอะมาก
// อนุญาตให้แก้ไขบทความนี้โดยเฉพาะ
Bouncer::allow($user)->to('edit', $post);
// อนุญาตให้ผู้ใช้แก้ไขบทความที่ตัวเองเป็นคนสร้าง
Bouncer::allow($user)->toOwn(Post::class)->to(['update']);
อธิบายโค้ด: บรรทัดแรกอนุญาตให้ผู้ใช้แก้ไข $post (บทความ) ที่ส่งเข้าไปได้โดยตรง ส่วนบรรทัดที่สองใช้คำสั่ง toOwn เพื่อบอกว่าถ้าใครเป็นเจ้าของบทความ (ผู้สร้าง) ให้ได้รับสิทธิ์แก้ไขโดยอัตโนมัติ
ผลลัพธ์: ระบบจะจดจำว่า $user มีสิทธิ์เฉพาะเจาะจงกับบทความนั้นๆ และทำงานร่วมกับคำสั่ง $user->can('update', $post) ได้ทันที
อย่าลืมใช้ Policy ควบคู่กันเสมอ
ไม่ว่าคุณจะเลือกแพ็กเกจไหน ทั้งสองตัวไม่ได้เข้ามาแทนที่ระบบ Policy ของ Laravel แต่เป็นเพียงตัวช่วยเสริมเท่านั้น ความผิดพลาดที่มือใหม่มักเจอคือการเอาโค้ดเช็คสิทธิ์ไปวางกระจายอยู่ทั่วใน Controller (ไฟล์ที่คอยควบคุมการทำงาน) ซึ่งทำให้แก้ไขยากมากในอนาคต
หลักการที่ดีคือให้คุณสร้าง Policy ขึ้นมา แล้วนำคำสั่งเช็คสิทธิ์จากแพ็กเกจที่คุณเลือกไปวางไว้ข้างในนั้น จากนั้นใน Controller ให้เรียกใช้แค่ Policy เท่านั้น วิธีนี้จะทำให้คุณเปลี่ยนแพ็กเกจได้ง่ายในอนาคตโดยไม่ต้องแก้โค้ดส่วนอื่นเลย
การใช้ Policy ยังช่วยให้โค้ดของคุณอ่านง่ายขึ้น เพราะเงื่อนไขต่างๆ จะถูกรวมไว้ที่เดียว ถ้าวันหนึ่งลูกค้าเปลี่ยนใจอยากเพิ่มเงื่อนไขว่า "ต้องเป็นบทความที่ยังไม่ถูกล็อกเท่านั้นถึงจะแก้ไขได้" คุณก็แค่มาแก้ในไฟล์ Policy ไฟล์เดียวเท่านั้น
public function update(User $user, Post $post): bool {
// เช็คสิทธิ์จากแพ็กเกจ และเช็คเงื่อนไขสถานะบทความ
return $user->can('edit articles') && $post->status !== 'locked';
}
อธิบายโค้ด: บรรทัดนี้เป็นการเขียนฟังก์ชันใน Policy ที่รวมเอาทั้งการเช็คสิทธิ์จากแพ็กเกจ (can) และเช็คสถานะของบทความ (status) เข้าด้วยกันก่อนจะคืนค่าเป็นจริงหรือเท็จ
ผลลัพธ์: หากบทความถูกล็อก สถานะจะเป็น false ทันที แม้ผู้ใช้จะมีสิทธิ์แก้ไขก็ตาม
สรุป: เลือกตัวไหนให้เหมาะกับโปรเจกต์
ถ้าคุณกำลังทำโปรเจกต์ทั่วไปที่สิทธิ์ส่วนใหญ่เป็นแบบ "กลุ่มนี้ทำสิ่งนี้ได้" ให้เลือก Spatie Permission เพราะมันเสถียร มีคนใช้เยอะ และหาคำตอบได้ง่ายมาก เหมาะกับมือใหม่ที่ต้องการความมั่นใจและเครื่องมือมาตรฐานที่ตลาดต้องการ
แต่ถ้าโปรเจกต์ของคุณเน้นเรื่องการเป็นเจ้าของข้อมูล (Ownership) หรือต้องการระบบจัดการสิทธิ์ที่ละเอียดถึงระดับข้อมูลแต่ละชิ้น ให้พิจารณา Bouncer เพราะมันจะช่วยประหยัดเวลาในการเขียนโค้ดเช็คสิทธิ์รายบุคคลไปได้มาก
ไม่ว่าเลือกตัวไหน หัวใจสำคัญคือการวางระบบผ่าน Policy อย่าเขียนโค้ดเช็คสิทธิ์ปนกับโค้ดสั่งงานใน Controller เด็ดขาด เพราะนั่นคือจุดเริ่มต้นของ "หนี้ทางเทคนิค" ที่จะทำให้คุณปวดหัวในอนาคต เลือกตัวที่ตอบโจทย์งานตอนนี้ แล้วโฟกัสที่การเขียนโค้ดให้สะอาดและอ่านง่ายก็พอครับ
ที่มา: Spatie Permission vs Bouncer: One Question Decides Which One You Need — DEV Community: laravel