ใช้เลขฐาน 2 ช่วยทำ User Access Control
หลังจากบทความเรื่องการประยุกต์ใช้เลขฐานในบทความก่อนหน้า ได้รับความนิยมอย่างล้นหลาม ผมก็นึกถึงบทความเก่าที่เคยเขียนเอาไว้ จึงขออนุญาตเอามา re-post อีกครั้ง จุดประสงค์เพื่อให้น้องๆ นักเรียน นักศึกษา ได้เห็นว่าคณิตศาสตร์นั้นเป็นวิชาที่ถ้าเรารู้จักเอามาใช้ มันก็มีประโยชน์มากมายนะ
ตั้งใจเรียน อย่ามองว่า เรียนไปทำไม ไม่ได้ใช้ เออน่า ใครจะรู้ สักวันเราจะได้ใช้มัน
เชื่อพี่ พี่เรียนมา 😂
ครูอาจารย์ท่านใด กำลังมองหาตัวอย่างการนำเอาคณิตศาสตร์มาประยุกต์ใช้ให้เกิดประโยชน์ สามารถนำบล็อกนี้เป็นอ้างอิงให้น้องๆ อ่านได้เลยครับ ด้วยความยินดี (แต่อย่าลอกข้อสอบแบบอาจารย์ท่านนี้นะ ไม่โอเค อายเค้า 55)
ผมอยากให้เด็กไทยนอกจากจะเรียนพีชคณิตแล้ว ต้องได้เห็นตัวอย่างการนำพีชคณิตไปประยุกต์ใช้ให้เกิดประโยชน์ด้วย ไม่มากก็น้อย แต่พวกเค้าต้องได้เห็น ให้มีทัศนคติต่อคณิตศาสตร์ที่ดีกว่านี้ คณิตศาสตร์มันไม่ได้เรียนไปเพื่อสอบ แต่มันเรียนไปเพื่อที่จะช่วยให้ชีวิตเค้าง่ายขึ้น
เข้าเรื่องเลย
เป็นเรื่องปกติที่ web application จะมี users หลายตำแหน่ง เช่น Administrator มีสิทธิ์แก้ไขข้อมูลได้ทุกหน้า ในขณะที่ Editor มีสิทธิ์เขียนบทความเฉพาะในหมวดที่ตนเองได้รับมอบหมาย การเขียนโปรแกรมเพื่อกรองสิทธิ์เหล่านี้เรียกว่า “User Access Control”
วิธีการทำ User Access Control นั้นมีมากมายหลายวิธี วิธีที่ง่ายๆ ก็แค่กำหนดสิทธิ์ตายตัวลงไปในโค้ดเลย แต่กับเว็บบางประเภท Requirements กลับซับซ้อนมากกว่านั้น เช่น ต้องการให้กำหนดสิทธิ์เข้าถึงเป็นรายบุคคลได้อย่าง Dynamic ผ่านระบบจัดการหลังบ้าน
ซึ่งโดยมากก็มักจะไปจบที่การทำ Table ของสิทธิ์แยกออกมา แล้วทำการโยงความสัมพันธ์ one-to-many ให้กับ user หรือ role นั้นๆ ว่าเข้าถึงหน้าไหนได้บ้าง
ฟังดูซับซ้อนใช่ไหมครับ? วันนี้ผมมีวิธีง่ายๆ มาแนะนำ
วิธีที่ผมจะมาแนะนำ เป็นการประยุกต์เอาเลขฐาน 2 มาเก็บข้อมูลแทนการทำ Table แยก โดยวิธีนี้ เราเพียงแค่เพิ่ม field เข้าไปใน Table ของ User อีก 1 field ขอตั้งชื่อว่า level ก็แล้วกัน
ค่า level จะเป็นตัวที่ชี้วัดได้ว่า user นี้มีสิทธิ์ในการเข้าอ่านหน้าไหนได้บ้าง
ต่อไปเป็นที่มาที่ไปของค่า level นะครับ ว่าจะหามาได้ยังไง แล้วเอาไปใช้ยังไง
วิธีสร้าง Level
สมมุติเว็บนี้มีทั้งหมด 10 หน้า แต่ละหน้ามี id ของตัวเองคือ 1 2 3 4 … 10 ตามลำดับ
ถ้า user คนนี้มีสิทธิ์เข้าอ่านได้แค่หน้าที่ 7 8 9 และ 10 เราจะได้ความสัมพันธ์ดังนี้
โดยที่ 0 หมายถึง ไม่มีสิทธิ์ และ 1 หมายถึงมีสิทธิ์เข้าอ่านได้
จากตารางดังกล่าว สิทธิ์ในการเข้าถึงก็คือ 0000001111
แต่อย่าเพิ่งนำไปใช้ ให้ทำการ reverse string เสียก่อน
เหตุผลที่ต้องกลับเลขเสียก่อน เพื่อให้ค่า Level ยังคงทำงานได้ถูกต้อง แม้จะมีการเพิ่มจำนวนหน้าเพิ่มเข้าไปอีก สำหรับคนที่สงสัย ก็ลองไม่กลับเลข > เพิ่มหน้าใหม่ แล้วลองคำนวณ Level ดูนะครับ จะพบว่า Level ที่คำนวณไว้ตอน 10 หน้ากับตอน 11 หน้า มันมีค่าต่างกันโดยสิ้นเชิง ทำให้เลข Level ที่คำนวณเอาไว้ก่อนหน้า ใช้ไม่ได้ทั้งหมด การกลับเลขจะแก้ปัญหานี้ได้ครับ
อีกเหตุผลเลยก็คือ เวลาเป็นตัวเลข เรานับหลักจากขวาไปซ้าย แต่ตารางด้านบนสังเกตว่าหลักที่ 1 คือหลักซ้ายสุด เราจึงต้อง reverse string เพื่อกลับให้หลักที่ 1 ไปอยู่ขวาสุดแทน จะได้นำไปคำนวณ Bitwise ได้ครับ
งงหรอ? ช่างมัน ไม่ต้องเข้าใจก็ได้ 55 เอาเป็นว่า ต้อง reverse string ด้วยนะครับ
สรุปว่า user ท่านนี้ มี level เท่ากับ 1111000000 นั่นเอง
โปรดสังเกตว่ามันคือเลขฐาน 2 ดีๆ นี่เอง ดังนั้น เพื่อไม่ให้มันยาวจนเกินไป ผมแนะนำให้แปลงเป็นเลขฐานอื่นเสีย เช่น ฐาน 10 (หรือฐาน 36 ไปเลย ในกรณีที่มีจำนวนหน้าเยอะมากๆ)
ผมเลือกเป็นฐาน 10 ละกัน จึงสรุปว่า user ท่านนี้จะมีสิทธิ์ (level) เท่ากับ 960
วิธีตีความ Level
ต่อไปเป็นการนำไปใช้นะครับ สมมุติเหตุการณ์ว่า user คนเดิม ต้องการเข้าอ่านข้อมูลหน้า ID = 4 เราจะรู้ได้อย่างไรว่าเค้ามีสิทธิ์อ่านหรือไม่?
เราก็ทำย้อนกลับเลยครับ โดยการแปลง level กลับไปเป็นเลขฐาน 2 จากนั้นก็กลับเลข
เช่นกรณีนี้ level คือ 960
960 ฐาน 2 คือ 1111000000 เมื่อกลับเลขแล้วจะได้ 0000001111
เสร็จแล้วก็เช็คเลขหลักที่ 4 ดูครับ ว่าเป็น 0 หรือเป็น 1
คำตอบคือเป็น 0 นั่นเอง แสดงว่าหน้านี้อ่านไม่ได้ครับ
เมื่อเข้าใจแล้ว มาเขียนโค้ดกัน
จากตัวอย่างเดิม level เป็น 960 อยากทราบว่า ID=4 มีสิทธิ์อ่านหรือไม่ ถ้าเอาแบบง่ายๆ เลย โค้ดก็จะประมาณนี้ครับ
ตัวอย่างภาษา JavaScript นะครับ ใครใช้ Node.js เอาไปใช้ได้เลย
var level = 960,
page_id = 4,
accessible;level = level.toString(2); // แปลงเป็นฐานสอง
level = level.split('').reverse().join(''); // ทำ string reverseaccessible = level[page_id-1] > 0;if (accessible) {
console.log('มีสิทธ์');
} else {
console.log('ไม่มีสิทธิ์');
}
หรือจะใช้ Bitwise operation เทียบค่าก็ได้ครับ แบบนี้ประสิทธิภาพจะดีกว่า แถมโค้ดจะสั้นกว่าด้วย (แนะนำให้ใช้แบบนี้มากกว่า)
var page_id = 4,
level = 960,
accessible = !!(level & 1 << (page_id - 1));if (accessible) {
console.log('มีสิทธ์');
} else {
console.log('ไม่มีสิทธิ์');
}
มีภาษา PHP แถมให้ด้วย สังเกตว่าเขียนเหมือน js เลย
$page_id = 4;
$level = 960;
$accessible = (bool) $level & 1 << ($page_id - 1);if ($accessible) {
echo 'มีสิทธ์';
} else {
echo 'ไม่มีสิทธิ์';
}
แบบหลังคำสั่งมันจะเข้าใจยากนิดนึงนะครับ เพราะค่อนข้าง low level เอาเป็นว่าเข้าใจคอนเซ็ปต์ก็โอเคแล้วครับ จะนำไป implement แบบไหนก็ค่อยว่ากันอีกที อาจจะใช้วิธี เช็คค่า string ไปทีละ char แบบในตัวอย่างแรกก็ได้
เป็นไง ง่ายไหมครับ? เข้าใจก็ง่าย เขียนโปรแกรมก็ง่าย แถมไม่เปลืองเนื้อที่ข้อมูลด้วย ถ้าจะประยุกต์เพิ่มเติม เพื่อแยกสิทธิ์เป็นประเภทๆ ก็ทำได้นะ เช่น สิทธ์ในการอ่าน สิทธิ์ในการแก้ไข ที่เราต้องทำก็แค่สร้าง field เพิ่มเพื่อเก็บ level แยกเป็นอย่างๆ ก็เท่านั้นเอง
หวังว่าบทความนี้จะช่วยให้เพื่อนๆ เห็นไอเดีย ในการประยุกต์เอาคณิตศาสตร์มาช่วยเขียนโปรแกรมเพิ่มอีกนะครับ
คณิตศาสตร์ + โปรแกรมมิ่ง = เวทย์มนต์ชัดๆ