การใช้ DDD: ผู้ใช้และการอนุญาต


16

ฉันกำลังทำงานกับแอปพลิเคชันขนาดเล็กที่พยายามเข้าใจหลักการของการออกแบบที่ขับเคลื่อนด้วยโดเมน หากประสบความสำเร็จนี่อาจเป็นโครงการนำร่องสำหรับโครงการขนาดใหญ่ ฉันกำลังพยายามติดตามหนังสือ "ใช้การออกแบบโดเมนขับเคลื่อนด้วย" (โดย Vaughn Vernon) และพยายามใช้ฟอรัมสนทนาที่คล้ายกันและเรียบง่าย ฉันได้ลองดูตัวอย่าง IDDD ของ GitHub ฉันมีปัญหาในการใช้ข้อมูลประจำตัวและการเข้าถึงกรณีของฉัน ให้ฉันให้ข้อมูลพื้นหลัง:

  • ฉัน (หวังว่า) เข้าใจเหตุผลที่อยู่เบื้องหลังการแยกผู้ใช้และตรรกะการอนุญาต: มันเป็นโดเมนที่สนับสนุนและเป็นบริบทที่แตกต่างกัน
  • ในโดเมนหลักไม่มีผู้ใช้เพียงแค่ผู้สร้างผู้ดูแล ฯลฯ สิ่งเหล่านี้ถูกสร้างขึ้นโดยการเข้าถึงบริบทผู้ใช้และการเข้าถึงโดยใช้บริการจากนั้นจึงแปลวัตถุผู้ใช้ที่ได้รับและผู้ดูแล
  • การดำเนินการกับโดเมนจะถูกเรียกพร้อมกับบทบาทที่เกี่ยวข้องเป็นพารามิเตอร์: เช่น:

    ModeratePost( ..., moderator);

  • วิธีการของวัตถุโดเมนตรวจสอบว่าอินสแตนซ์ของโมเดอเรเตอร์ที่กำหนดไม่ใช่โมฆะ (อินสแตนซ์ของโมเดอเรเตอร์จะเป็นโมฆะถ้าผู้ใช้ที่ถามจากบริบทผู้ใช้และบริบทไม่มีบทบาทผู้ดูแล)

  • ในกรณีหนึ่งจะทำการตรวจสอบเพิ่มเติมก่อนที่จะแก้ไขโพสต์:

    if (forum.IsModeratedby(moderator))

คำถามของฉันคือ:

  • ในกรณีหลังความกังวลด้านความปลอดภัยไม่ได้รวมกันอีกครั้งในโดเมนหลัก? ก่อนหน้านี้หนังสือระบุว่า "ใครสามารถโพสต์หัวข้อหรือภายใต้เงื่อนไขที่อนุญาตฟอรั่มเพียงแค่ต้องรู้ว่าผู้แต่งกำลังทำเช่นนั้นในตอนนี้"

  • การนำไปใช้ตามบทบาทในหนังสือเล่มนี้ค่อนข้างตรงไปตรงมา: เมื่อ Moderator เป็นโดเมนหลักพยายามแปลง userId ปัจจุบันเป็น Moderator หรือเป็นผู้เขียนเมื่อต้องการ บริการจะตอบกลับด้วยอินสแตนซ์ที่เหมาะสมหรือเป็นโมฆะหากผู้ใช้ไม่มีบทบาทที่จำเป็น อย่างไรก็ตามฉันไม่สามารถเห็นได้ว่าฉันจะปรับให้เข้ากับรูปแบบการรักษาความปลอดภัยที่ซับซ้อนมากขึ้นได้อย่างไร โครงการปัจจุบันของเราที่ฉันกำลังดำเนินการอยู่นั้นมีรูปแบบที่ค่อนข้างซับซ้อนกับกลุ่ม ACL ฯลฯ

แม้จะมีกฎที่ไม่ซับซ้อนมากเช่น: "โพสต์ควรแก้ไขโดยเจ้าของหรือบรรณาธิการเท่านั้น" วิธีการนี้ดูเหมือนจะพังหรืออย่างน้อยฉันก็ไม่เห็นวิธีที่ถูกต้องในการนำไปใช้

โดยการถามบริบท Identity and Access สำหรับอินสแตนซ์ OwnerOrEditor รู้สึกไม่ถูกต้องและฉันจะจบลงด้วยคลาสที่เกี่ยวข้องกับความปลอดภัยมากขึ้นในโดเมนหลัก นอกจากนี้ฉันจะต้องผ่านไม่ใช่ userId เท่านั้น แต่ตัวระบุของทรัพยากรที่มีการป้องกัน (id ของโพสต์ฟอรัม ฯลฯ ) ไปยังบริบทความปลอดภัยซึ่งอาจไม่ควรสนใจสิ่งเหล่านี้ (ถูกต้องหรือไม่? )

ด้วยการดึงสิทธิ์ไปยังโดเมนหลักและตรวจสอบพวกเขาในวิธีการของวัตถุโดเมนหรือในบริการฉันจะสิ้นสุดที่ตารางที่หนึ่ง: การผสมความกังวลด้านความปลอดภัยกับโดเมน

ฉันได้อ่านที่ไหนสักแห่ง (และฉันมักจะเห็นด้วยกับมัน) ว่าสิ่งเหล่านี้เกี่ยวข้องกับการอนุญาตไม่ควรเป็นส่วนหนึ่งของโดเมนหลักยกเว้นว่าการรักษาความปลอดภัยและการอนุญาตเป็นโดเมนหลักเอง กฎอย่างง่าย ๆ เช่นเดียวกับที่ระบุไว้ข้างต้นแสดงให้เห็นถึงการรักษาความปลอดภัยเป็นส่วนหนึ่งของโดเมนหลักหรือไม่?


บางทีคุณสามารถค้นหาสิ่งที่คุณต้องการได้ที่นี่: stackoverflow.com/a/23485141/329660นอกจากนี้เนื่องจากบริบทการควบคุมการเข้าถึงรู้เกี่ยวกับIDทรัพยากรไม่ได้หมายความว่ามีความรู้ในโดเมนเกี่ยวกับเอนทิตีที่เป็นประเภทของทรัพยากรหรืออะไร ทำ.
guillaume31

ขอบคุณฉันเคยเห็นโพสต์ก่อนหน้านี้ปัญหาของฉันคือสิ่งที่การแก้ไขระบุไว้ในตอนท้าย: ฉันต้องการย้ายการควบคุมการเข้าถึงออกจากโดเมนหลักของฉัน แต่ฉันรู้สึกว่าฉันประสบความสำเร็จในการติดตั้ง อย่างไรก็ตามข้อเสนอแนะของคุณเกี่ยวกับ ID ทรัพยากรเหมาะสม: เนื่องจากฉันไม่ได้ใช้แนวคิดของผู้ใช้หรือบทบาทในโดเมนหลัก แต่มีบทบาทที่เป็นรูปธรรมบางทีฉันอาจใช้แนวคิดของทรัพยากรในการรักษาความปลอดภัย BC และแมปกับคอนกรีตที่เกี่ยวข้อง แนวคิดโดเมน คุ้มค่าลองขอบคุณ!
LittlePilgrim

ตัวอย่างรหัสในลิงก์อย่างน้อยตอบคำถามที่ว่า "ฉันไม่สามารถเห็นได้ว่าฉันจะปรับให้เข้ากับรูปแบบการรักษาความปลอดภัยที่ซับซ้อนมากขึ้น" ได้อย่างไร
guillaume31

ปัญหาของฉันไม่ได้เกิดจากการนำโมเดลความปลอดภัยมาใช้ฉันไม่สามารถดูได้ว่าฉันควรทำแผนที่กฎที่ซับซ้อนเหล่านี้ในโดเมนได้อย่างไร การแมปผู้ใช้ -> ผู้แต่งควรเปลี่ยนแปลงอย่างไรถ้าไม่ใช่แบบจำลองบทบาทที่เรียบง่ายในด้านความปลอดภัย การส่งรหัสทรัพยากรไปยังบริบทอื่นอาจใช้งานได้เช่นHasPermissionToEdit(userId, resourceId)แต่ฉันรู้สึกไม่ถูกต้องที่จะปนเปื้อนตรรกะโดเมนด้วยการเรียกเหล่านี้ อาจฉันควรตรวจสอบสิ่งเหล่านี้ในวิธีการบริการแอปพลิเคชันก่อนที่จะเรียกตรรกะโดเมน?
LittlePilgrim

แน่นอนว่ามันควรจะอยู่ในบริการแอปพลิเคชัน ... ฉันคิดว่ามันชัดเจนจากบางส่วนของรหัสเช่นUserService @AccessControlList[inf3rno]ในคำตอบที่ฉันเชื่อมโยง
guillaume31

คำตอบ:


6

บางครั้งก็ยากที่จะแยกแยะความแตกต่างระหว่างกฎการควบคุมการเข้าถึงจริงและค่าคงที่โดเมนในการควบคุมการเข้าถึง

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

assert (forum.IsModeratedBy(moderator))ตัวอย่างของ Vaughn Vernon น่าจะอยู่นอกโดเมน แต่ไม่เป็นไปได้เสมอไป

ฉันจะต้องผ่านไม่ใช่แค่ userId เท่านั้น แต่ตัวระบุของทรัพยากรที่ได้รับการปกป้อง (id ของโพสต์ฟอรัม ฯลฯ ) ไปยังบริบทความปลอดภัยซึ่งอาจไม่ควรสนใจสิ่งเหล่านี้ (ถูกต้องหรือไม่)

หากมี Security BC และคุณต้องการให้จัดการกับตรรกะนั้นก็ไม่จำเป็นต้องรู้ว่าฟอรัมมีรายละเอียดอะไร แต่:

  • มันอาจมีความรู้เกี่ยวกับแนวคิดเช่น "กลั่นกรองโดย" และให้หรือปฏิเสธสิทธิ์การเข้าถึงตามลำดับ
  • คุณสามารถมีอะแดปเตอร์แบบลอจิคัลที่สมัครสมาชิกกิจกรรม Core Domain และแปลเป็นคู่ค่าคีย์แบบง่าย (ทรัพยากร, ผู้ใช้ที่ได้รับอนุญาต) สำหรับ Security BC เพื่อเก็บและใช้

เนื่องจากคำตอบทั้งสองมีประโยชน์และมากกว่าหรือน้อยกว่าชี้ไปในทิศทางเดียวกันฉันจึงยกทั้งสองขึ้นมา ฉันยอมรับสิ่งนี้เนื่องจาก @ guillaume31 ตอบคำถามของฉันเกี่ยวกับการใช้งานเวอร์นอนน้อยลงและฉันจะดำเนินการต่อไปตามคำแนะนำเกี่ยวกับการใช้ทรัพยากรใน Security BC
LittlePilgrim

ฉันต้องบอกว่าฉันคิดว่านี่ตรงข้ามกับคำตอบของฉัน
Ewan

1
บางทีฉันสับสนเกินไปในตอนนี้ แต่การตีความของฉันคือ (สำหรับทั้งสองคำตอบ): 1. รักษาความปลอดภัยออกจากโดเมนและใช้ BC การรักษาความปลอดภัยเป็นบริการ 2. เรียกบริการก่อนเรียกใช้วัตถุโดเมนใด ๆ 3. บริการ จะทำการแมปจากผู้ใช้ / acls ถึงผู้ดูแลผู้เขียน ฯลฯmoderator = securityService.GetModerator(userId, forumId) 4. ตรรกะของโดเมนจะถูกนำไปใช้ในวัตถุเหล่านี้เช่นเดียวกับใน moderatorEditPost () 5. วิธีการเช่น EditPost จะไม่รู้อะไรเกี่ยวกับแนวคิดด้านความปลอดภัยจะไม่มีการตรวจสอบเพิ่มเติม มี
LittlePilgrim

ฉันยังคงหาคำตอบ / ทิศทางเกี่ยวกับเรื่องนี้ด้วยตัวเอง แต่ฉันพบว่าตรรกะการอนุญาตใด ๆ ที่อาศัยสถานะปัจจุบันของวัตถุ (เช่นถ้ามันได้รับมอบหมายให้ผู้ดำเนินรายการ) เป็นตรรกะทางธุรกิจที่เป็นของจริง โดเมนของคุณและเพิ่มเติมว่าหากไม่ได้อยู่ในโดเมนของคุณคุณมีความเสี่ยงที่จะสิ้นสุดในสถานะที่ไม่ถูกต้องหากสามารถอัปเดตโมเดลพร้อมกันได้ ตัวอย่างเช่นหากคุณตรวจสอบความเป็นเจ้าของโดยใช้นโยบายจากนั้นไปที่อัปเดตวัตถุนั้น - ในหลายโดเมนที่ความเป็นเจ้าของอาจมีการเปลี่ยนแปลงและการกระทำอาจไม่ถูกต้องอีกต่อไป
Jordan

หากคุณไม่มีบริบทการทำงานร่วมกันที่ซับซ้อนมากคุณอาจจะสามารถใช้โมเดลการทำงานพร้อมกันในแง่ดีที่นี่โดยใช้การกำหนดเวอร์ชัน แต่ถ้าเช็คของคุณไม่ได้ทำภายในหรืออย่างน้อยเทียบกับอินสแตนซ์รวมที่เฉพาะเจาะจง สถานะของวัตถุตามเวลาที่คุณยืนยันการเปลี่ยนแปลงของคุณ
Jordan

5

การพิสูจน์ตัวตนและการอนุญาตเป็นตัวอย่างที่ไม่ดีสำหรับ DDD

ไม่มีสิ่งเหล่านี้เป็นส่วนหนึ่งของโดเมนเว้นแต่ว่า บริษัท ของคุณจะสร้างผลิตภัณฑ์รักษาความปลอดภัย

ข้อกำหนดของธุรกิจหรือโดเมนคือหรือควรเป็น "ฉันต้องการการรับรองความถูกต้องตามบทบาท"

จากนั้นคุณตรวจสอบบทบาทก่อนเรียกใช้ฟังก์ชันโดเมน

ที่ที่คุณมีข้อกำหนดที่ซับซ้อนเช่น 'ฉันสามารถแก้ไขโพสต์ของตัวเอง แต่ไม่ใช่คนอื่น' ตรวจสอบให้แน่ใจว่าโดเมนของคุณแยกฟังก์ชันแก้ไขออกเป็นEditOwnPost()และEditOthersPost()เพื่อให้คุณมีฟังก์ชั่นที่ง่ายในการทำแผนที่บทบาท

คุณยังสามารถแยกฟังก์ชันการทำงานออกเป็น Domain Objects เช่น Poster.EditPost()และModerator.EditPost()นี่เป็นวิธีการแบบ OOP ที่มากขึ้นถึงแม้ว่าตัวเลือกของคุณอาจขึ้นอยู่กับว่าวิธีการของคุณอยู่ในบริการโดเมนหรือ Domain Object

อย่างไรก็ตามคุณเลือกที่จะแยกรหัสซึ่งการแมปบทบาทจะเกิดขึ้นนอกโดเมน เช่นถ้าคุณมีตัวควบคุม webapi:

PostController : ApiController
{
    [Authorize(Roles = "User")]
    public void EditOwnPost(string postId, string newContent)
    {
        this.postDomainService.EditOwnPost(postId, string newContent);
    }

    [Authorize(Roles = "Moderator")]
    public void EditOtherPost(string postId, string newContent)
    {
        this.postDomainService.EditOtherPost(postId, string newContent);
    }
}

อย่างที่คุณเห็นแม้ว่าการแมปบทบาทจะทำบนโฮสติ้งเลเยอร์ แต่ตรรกะที่ซับซ้อนของสิ่งที่ถือเป็นการแก้ไขของคุณเองหรือโพสต์อื่น ๆเป็นส่วนหนึ่งของโดเมน

โดเมนตระหนักถึงความแตกต่างของการกระทำ แต่ความต้องการของการรักษาความปลอดภัยก็คือว่า"การทำงานสามารถถูก จำกัด โดยบทบาท"

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


4
การตรวจสอบบทบาท "แบบคงที่" นั้นค่อนข้างง่าย จะทำอย่างไรถ้าผู้ดูแลไม่ได้รับอนุญาตให้แก้ไขโพสต์ของผู้ดูแลคนอื่น? การตรวจสอบนี้ไม่ควรเป็นส่วนหนึ่งของโดเมนใช่หรือไม่
Réda Housni Alaoui

2
@ RédaHousniAlaouiฉันสงสัยเกี่ยวกับเรื่องนี้เช่นกัน ฉันไม่สามารถคิดวิธีจัดการกับสิ่งนี้ได้นอกจากจะรวมถึงการกล่าวถึงผู้ใช้ / ผู้ดูแลในโดเมนหรือดำเนินการตรรกะบางอย่างภายใน ApiController นั้นเพื่อรับบทบาทของผู้เขียนโพสต์ สิ่งเหล่านี้ดูเหมือนจะไม่ถูกต้องและนี่ก็เป็นเรื่องธรรมดามากพอในประสบการณ์ของฉันว่าคำแนะนำที่ชัดเจนบางอย่างจะเป็นประโยชน์อย่างยิ่ง
Jimmy

1
@Erwan กรณีการใช้งานที่ฉันพูดถึงนั้นเป็นแบบไดนามิก การอ้างอิงประโยค "การพิสูจน์ตัวตนและการอนุญาตเป็นตัวอย่างที่ไม่ดีสำหรับ DDD" ในตัวอย่างสวัสดีโลกนั้นไม่สุจริต DDD อยู่ที่นี่เพื่อหลีกเลี่ยงความซับซ้อนโดยไม่ได้ตั้งใจและอนุญาตให้จัดการความซับซ้อนของโดเมน สิทธิ์แบบไดนามิกไม่ได้มีความซับซ้อนโดยไม่ตั้งใจหรือสิ่งที่ไม่ได้เกิดขึ้นในชีวิตจริง
Réda Housni Alaoui

1
IMHO ปัญหาเกี่ยวกับโซลูชันของคุณคือไม่พอใจลูกค้า ลูกค้ามักต้องการเปลี่ยนความสัมพันธ์เหล่านั้นแบบไดนามิก ยิ่งไปกว่านั้นนั่นคือสิ่งที่จะเกิดขึ้นเมื่อผู้ขายจัดหาซอฟต์แวร์องค์กรเดียวกันให้กับ บริษัท ต่างๆ หากซอฟต์แวร์บิดได้ไม่ดีผู้ขายก็จะตายในที่สุด
Réda Housni Alaoui

1
"แต่โดยทั่วไปแล้วจะได้รับการยอมรับว่าเป็น" สิ่งเลวร้าย "การตั้งค่าความปลอดภัยของคุณจะไม่สามารถจัดการได้ตลอดเวลาซึ่งหมายความว่าแอปของคุณจะไม่ปลอดภัย" ด้วยการออกแบบและทดสอบที่ถูกต้องจึงสามารถจัดการได้ทั้งหมด แต่จาก XP ของฉันเพื่อสร้างการออกแบบที่ถูกต้องโดเมนจะต้องตรวจสอบสิทธิ์ ทางเลือกคือยูโทเปีย
Réda Housni Alaoui
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.