ACL และคอนโทรลเลอร์
ประการแรกสิ่งเหล่านี้เป็นสิ่งที่แตกต่างกัน / ชั้นบ่อยที่สุด ในขณะที่คุณวิจารณ์โค้ดคอนโทรลเลอร์ที่เป็นแบบอย่างมันทำให้ทั้งสองอย่างเข้าด้วยกันซึ่งเห็นได้ชัดว่าแน่นเกินไป
tereškoได้อธิบายถึงวิธีที่คุณสามารถแยกสิ่งนี้ได้มากขึ้นด้วยรูปแบบมัณฑนากร
ฉันจะย้อนกลับไปหนึ่งก้าวก่อนเพื่อค้นหาปัญหาเดิมที่คุณกำลังเผชิญอยู่และพูดคุยกันสักหน่อย
ในแง่หนึ่งคุณต้องการมีคอนโทรลเลอร์ที่ทำงานตามคำสั่ง (คำสั่งหรือการกระทำเรียกว่าคำสั่ง)
ในทางกลับกันคุณต้องการให้สามารถใส่ ACL ในแอปพลิเคชันของคุณได้ สาขาการทำงานของ ACL เหล่านี้ควรเป็น - ถ้าฉันเข้าใจคำถามของคุณถูกต้อง - เพื่อควบคุมการเข้าถึงคำสั่งบางคำของแอปพลิเคชันของคุณ
การควบคุมการเข้าถึงแบบนี้จึงต้องการสิ่งอื่นที่นำทั้งสองมารวมกัน ขึ้นอยู่กับบริบทที่มีการเรียกใช้คำสั่ง ACL จะเริ่มทำงานและต้องทำการตัดสินใจว่าคำสั่งเฉพาะสามารถดำเนินการโดยหัวเรื่องเฉพาะได้หรือไม่ (เช่นผู้ใช้)
สรุปสิ่งที่เรามี:
ส่วนประกอบ ACL เป็นศูนย์กลางที่นี่: อย่างน้อยต้องรู้บางอย่างเกี่ยวกับคำสั่ง (เพื่อระบุคำสั่งให้แม่นยำ) และต้องสามารถระบุผู้ใช้ได้ โดยปกติผู้ใช้จะระบุได้ง่ายด้วย ID เฉพาะ แต่บ่อยครั้งในแอปพลิเคชันบนเว็บจะมีผู้ใช้ที่ไม่ได้ระบุตัวตนเลยซึ่งมักเรียกว่าแขกไม่ระบุชื่อทุกคนเป็นต้นสำหรับตัวอย่างนี้เราถือว่า ACL สามารถใช้วัตถุผู้ใช้และห่อหุ้มรายละเอียดเหล่านี้ออกไปได้ อ็อบเจ็กต์ผู้ใช้ถูกผูกไว้กับอ็อบเจ็กต์คำร้องขอแอ็พพลิเคชันและ ACL สามารถใช้งานได้
แล้วการระบุคำสั่งล่ะ? การตีความรูปแบบ MVC ของคุณแสดงให้เห็นว่าคำสั่งประกอบด้วยชื่อคลาสและชื่อวิธีการ หากเรามองอย่างใกล้ชิดมากขึ้นจะมีแม้แต่อาร์กิวเมนต์ (พารามิเตอร์) สำหรับคำสั่ง ดังนั้นจึงถูกต้องที่จะถามว่าอะไรระบุคำสั่ง? ชื่อคลาสชื่อวิธีการจำนวนหรือชื่อของอาร์กิวเมนต์แม้แต่ข้อมูลภายในอาร์กิวเมนต์ใด ๆ หรือส่วนผสมของทั้งหมดนี้?
ขึ้นอยู่กับระดับของรายละเอียดที่คุณต้องระบุคำสั่งใน ACL'ing ของคุณสิ่งนี้อาจแตกต่างกันไปมาก สำหรับตัวอย่างขอให้เรียบง่ายและระบุว่าคำสั่งถูกระบุโดยชื่อคลาสและชื่อวิธีการ
ดังนั้นบริบทของทั้งสามส่วนนี้ (ACL, Command และ User) เป็นของกันและกันจึงชัดเจนมากขึ้น
เราสามารถพูดได้ด้วยส่วนประกอบ ACL ในจินตนาการเราสามารถทำสิ่งต่อไปนี้ได้แล้ว:
$acl->commandAllowedForUser($command, $user);
ดูสิ่งที่เกิดขึ้นได้ที่นี่: ด้วยการทำให้ทั้งคำสั่งและผู้ใช้สามารถระบุตัวตนได้ ACL ก็สามารถทำงานได้ งานของ ACL ไม่เกี่ยวข้องกับการทำงานของทั้งอ็อบเจ็กต์ผู้ใช้และคำสั่งคอนกรีต
มีเพียงส่วนเดียวที่หายไปนี้ไม่สามารถมีชีวิตอยู่ในอากาศได้ และมันไม่ได้ ดังนั้นคุณต้องค้นหาสถานที่ที่จำเป็นต้องใช้การควบคุมการเข้าถึงลองมาดูว่าเกิดอะไรขึ้นในแอปพลิเคชันเว็บมาตรฐาน:
User -> Browser -> Request (HTTP)
-> Request (Command) -> Action (Command) -> Response (Command)
-> Response(HTTP) -> Browser -> User
ในการค้นหาสถานที่นั้นเรารู้ว่ามันต้องอยู่ก่อนที่จะดำเนินการคำสั่งที่เป็นรูปธรรมดังนั้นเราจึงสามารถลดรายการนั้นและต้องดูที่ (ที่เป็นไปได้) ต่อไปนี้
User -> Browser -> Request (HTTP)
-> Request (Command)
เมื่อถึงจุดหนึ่งในแอปพลิเคชันของคุณคุณทราบว่ามีผู้ใช้บางรายร้องขอให้ดำเนินการคำสั่งที่เป็นรูปธรรม คุณทำ ACL บางประเภทที่นี่แล้ว: หากผู้ใช้ร้องขอคำสั่งที่ไม่มีอยู่คุณจะไม่อนุญาตให้คำสั่งนั้นดำเนินการ ดังนั้นสิ่งที่เกิดขึ้นในแอปพลิเคชันของคุณอาจเป็นจุดที่ดีในการเพิ่มการตรวจสอบ ACL "จริง":
คำสั่งถูกระบุไว้และเราสามารถสร้างรหัสประจำตัวเพื่อให้ ACL จัดการกับมันได้ ในกรณีที่ไม่อนุญาตให้ใช้คำสั่งสำหรับผู้ใช้คำสั่งจะไม่ถูกดำเนินการ (action) อาจจะCommandNotAllowedResponse
แทนCommandNotFoundResponse
สำหรับกรณีที่คำขอไม่สามารถแก้ไขเป็นคำสั่งคอนกรีต
สถานที่ที่ทำแผนที่ของคอนกรีต HttpRequest ถูกแมปบนคำสั่งมักจะเรียกว่าการกำหนดเส้นทาง เนื่องจากRoutingมีงานในการค้นหาคำสั่งอยู่แล้วทำไมไม่ขยายเพื่อตรวจสอบว่าคำสั่งนั้นได้รับอนุญาตจริงต่อ ACL หรือไม่ เช่นโดยการขยายRouter
ไปยังเราเตอร์ ACL ที่รับรู้: RouterACL
. หากเราเตอร์ของคุณยังไม่ทราบUser
แล้วRouter
ไม่ได้เป็นสถานที่ที่เหมาะสมเพราะสำหรับ ACL'ing ในการทำงานไม่เพียง แต่คำสั่ง แต่ยังผู้ใช้จะต้องระบุ ดังนั้นสถานที่นี้อาจแตกต่างกันไป แต่ฉันแน่ใจว่าคุณสามารถค้นหาสถานที่ที่คุณต้องการขยายได้อย่างง่ายดายเพราะเป็นสถานที่ที่เติมเต็มความต้องการของผู้ใช้และคำสั่ง:
User -> Browser -> Request (HTTP)
-> Request (Command)
ผู้ใช้สามารถใช้ได้ตั้งแต่เริ่มต้น Command first ด้วยRequest(Command)
.
ดังนั้นแทนที่จะใส่การตรวจสอบ ACL ของคุณในการใช้งานที่เป็นรูปธรรมของแต่ละคำสั่งให้วางไว้ก่อน คุณไม่จำเป็นต้องมีรูปแบบที่หนักหน่วงเวทมนตร์หรืออะไรก็ตาม ACL ทำงานได้ดีผู้ใช้ทำงานได้ดีและโดยเฉพาะอย่างยิ่งคำสั่งก็ทำงานได้: แค่คำสั่งไม่มีอะไรอื่น คำสั่งไม่มีความสนใจที่จะทราบว่ามีการใช้บทบาทหรือไม่หากได้รับการปกป้องไว้ที่ใดที่หนึ่งหรือไม่
ดังนั้นแค่แยกสิ่งที่ไม่เป็นของกันและกัน ใช้หลักการความรับผิดชอบเดี่ยว (SRP)ซ้ำเล็กน้อย: ควรมีเหตุผลเดียวที่จะเปลี่ยนคำสั่ง - เนื่องจากคำสั่งมีการเปลี่ยนแปลง ไม่ใช่เพราะตอนนี้คุณแนะนำ ACL'ing ในแอปพลิเคชันของคุณ ไม่ใช่เพราะคุณเปลี่ยนวัตถุผู้ใช้ ไม่ใช่เพราะคุณย้ายจากอินเทอร์เฟซ HTTP / HTML ไปยัง SOAP หรืออินเทอร์เฟซบรรทัดคำสั่ง
ACL ในกรณีของคุณควบคุมการเข้าถึงคำสั่งไม่ใช่คำสั่งเอง
if($user->hasFriend($other_user) || $other_user->profileIsPublic()) $other_user->renderProfile()
(อื่นแสดงว่า "คุณไม่มีสิทธิ์เข้าถึงโปรไฟล์ของผู้ใช้คนนี้" หรืออะไรทำนองนั้นฉันไม่เข้าใจ