ฉันจะติดตั้ง Access Control List ในแอปพลิเคชัน Web MVC ของฉันได้อย่างไร


96

คำถามแรก

โปรดอธิบายฉันได้ไหมว่า ACL ที่ง่ายที่สุดสามารถนำไปใช้ใน MVC ได้อย่างไร

นี่คือแนวทางแรกของการใช้ Acl ใน Controller ...

<?php
class MyController extends Controller {

  public function myMethod() {        
    //It is just abstract code
    $acl = new Acl();
    $acl->setController('MyController');
    $acl->setMethod('myMethod');
    $acl->getRole();
    if (!$acl->allowed()) die("You're not allowed to do it!");
    ...    
  }

}
?>

มันเป็นแนวทางที่แย่มากและสิ่งที่ลบคือเราต้องเพิ่มชิ้นส่วนของ Acl ลงในวิธีการของคอนโทรลเลอร์แต่ละตัว แต่เราไม่ต้องการการอ้างอิงเพิ่มเติม!

แนวทางต่อไปคือการสร้างวิธีการทั้งหมดของคอนโทรลเลอร์privateและเพิ่มรหัส ACL ลงใน__callวิธีการของคอนโทรลเลอร์

<?php
class MyController extends Controller {

  private function myMethod() {
    ...
  }

  public function __call($name, $params) {
    //It is just abstract code
    $acl = new Acl();
    $acl->setController(__CLASS__);
    $acl->setMethod($name);
    $acl->getRole();
    if (!$acl->allowed()) die("You're not allowed to do it!");
    ...   
  }

}
?>

มันดีกว่ารหัสก่อนหน้า แต่ข้อเสียหลักคือ ...

  • วิธีการทั้งหมดของคอนโทรลเลอร์ควรเป็นแบบส่วนตัว
  • เราต้องเพิ่มรหัส ACL ลงในวิธี __call ของคอนโทรลเลอร์แต่ละตัว

แนวทางต่อไปคือการใส่รหัส Acl ลงในตัวควบคุมหลัก แต่เรายังคงต้องเก็บวิธีการควบคุมลูกทั้งหมดไว้เป็นส่วนตัว

วิธีแก้คืออะไร? และแนวทางปฏิบัติที่ดีที่สุดคืออะไร? ฉันควรเรียกใช้ฟังก์ชัน Acl ที่ไหนเพื่อตัดสินใจอนุญาตหรือไม่อนุญาตให้ดำเนินการวิธีการ

คำถามที่สอง

คำถามที่สองเกี่ยวกับการรับบทบาทโดยใช้ Acl ลองจินตนาการว่าเรามีแขกผู้ใช้และเพื่อนของผู้ใช้ ผู้ใช้ได้ จำกัด การเข้าถึงเพื่อดูโปรไฟล์ของเขาซึ่งมีเพียงเพื่อนเท่านั้นที่สามารถดูได้ แขกทุกคนไม่สามารถดูโปรไฟล์ของผู้ใช้รายนี้ นี่คือตรรกะ ..

  • เราต้องตรวจสอบให้แน่ใจว่าวิธีการที่เรียกนั้นเป็นโปรไฟล์
  • เราต้องตรวจหาเจ้าของโปรไฟล์นี้
  • เราต้องตรวจสอบว่าผู้ชมเป็นเจ้าของโปรไฟล์นี้หรือไม่
  • เราต้องอ่านกฎข้อ จำกัด เกี่ยวกับโปรไฟล์นี้
  • เราต้องตัดสินใจว่าจะดำเนินการหรือไม่ดำเนินการวิธีการโปรไฟล์

คำถามหลักเกี่ยวกับการตรวจหาเจ้าของโปรไฟล์ เราสามารถตรวจจับได้ว่าใครเป็นเจ้าของโปรไฟล์ที่เรียกใช้เมธอด $ model-> getOwner () ของโมเดลเท่านั้น แต่ Acl ไม่สามารถเข้าถึงโมเดลได้ เราจะนำสิ่งนี้ไปใช้ได้อย่างไร?

ฉันหวังว่าความคิดของฉันจะชัดเจน ขออภัยสำหรับภาษาอังกฤษของฉัน

ขอบคุณ.


1
ฉันไม่เข้าใจด้วยซ้ำว่าทำไมคุณถึงต้องมี "รายการควบคุมการเข้าถึง" สำหรับการโต้ตอบกับผู้ใช้ คุณจะไม่พูดอะไรเช่นif($user->hasFriend($other_user) || $other_user->profileIsPublic()) $other_user->renderProfile()(อื่นแสดงว่า "คุณไม่มีสิทธิ์เข้าถึงโปรไฟล์ของผู้ใช้คนนี้" หรืออะไรทำนองนั้นฉันไม่เข้าใจ
Buttle Butkus

2
อาจเป็นเพราะ Kirzilla ต้องการจัดการเงื่อนไขทั้งหมดสำหรับการเข้าถึงในที่เดียว - ส่วนใหญ่เป็นการกำหนดค่า ดังนั้นการเปลี่ยนแปลงสิทธิ์ใด ๆ สามารถทำได้ในผู้ดูแลระบบแทนที่จะเปลี่ยนรหัส
Mariyo

คำตอบ:


185

ส่วนแรก / คำตอบ (การใช้ ACL)

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

class SecureContainer
{

    protected $target = null;
    protected $acl = null;

    public function __construct( $target, $acl )
    {
        $this->target = $target;
        $this->acl = $acl;
    }

    public function __call( $method, $arguments )
    {
        if ( 
             method_exists( $this->target, $method )
          && $this->acl->isAllowed( get_class($this->target), $method )
        ){
            return call_user_func_array( 
                array( $this->target, $method ),
                $arguments
            );
        }
    }

}

และนี่จะเป็นวิธีที่คุณใช้โครงสร้างประเภทนี้:

// assuming that you have two objects already: $currentUser and $controller
$acl = new AccessControlList( $currentUser );

$controller = new SecureContainer( $controller, $acl );
// you can execute all the methods you had in previous controller 
// only now they will be checked against ACL
$controller->actionIndex();

อย่างที่คุณสังเกตเห็นโซลูชันนี้มีข้อดีหลายประการ:

  1. การกักกันสามารถใช้กับวัตถุใดก็ได้ไม่ใช่แค่อินสแตนซ์ของ Controller
  2. ตรวจสอบการอนุญาตเกิดขึ้นนอกวัตถุเป้าหมายซึ่งหมายความว่า:
    • ออบเจ็กต์ดั้งเดิมไม่รับผิดชอบต่อการควบคุมการเข้าถึงยึดตามSRP
    • เมื่อคุณได้รับ "การอนุญาตถูกปฏิเสธ" คุณไม่ได้ถูกล็อคอยู่ในตัวควบคุมตัวเลือกเพิ่มเติม
  3. คุณสามารถฉีดอินสแตนซ์ที่ปลอดภัยนี้ในออบเจ็กต์อื่นได้มันจะยังคงการป้องกันไว้
  4. ห่อมันและลืมไป .. คุณสามารถแสร้งทำเป็นว่ามันเป็นวัตถุดั้งเดิมมันก็จะตอบสนองเหมือนกัน

แต่ก็มีปัญหาสำคัญอย่างหนึ่งของวิธีนี้เช่นกัน - คุณไม่สามารถตรวจสอบได้ว่าการใช้งานวัตถุและอินเทอร์เฟซที่ปลอดภัย (ซึ่งใช้สำหรับการค้นหาวิธีการที่มีอยู่) หรือเป็นส่วนหนึ่งของห่วงโซ่การสืบทอด

ส่วนที่สอง / คำตอบ (RBAC สำหรับวัตถุ)

ในกรณีนี้ความแตกต่างหลักที่คุณควรทราบคือDomain Objects ของคุณ(ในตัวอย่างProfile:) มีรายละเอียดเกี่ยวกับเจ้าของ ซึ่งหมายความว่าเพื่อให้คุณตรวจสอบว่า (และในระดับใด) ผู้ใช้สามารถเข้าถึงได้คุณจะต้องเปลี่ยนบรรทัดนี้:

$this->acl->isAllowed( get_class($this->target), $method )

โดยพื้นฐานแล้วคุณมีสองทางเลือก:

  • ระบุ ACL กับวัตถุที่เป็นปัญหา แต่คุณต้องระวังอย่าละเมิดLaw of Demeter :

    $this->acl->isAllowed( get_class($this->target), $method )
    
  • ขอรายละเอียดที่เกี่ยวข้องทั้งหมดและให้ ACL ตามสิ่งที่ต้องการเท่านั้นซึ่งจะทำให้การทดสอบหน่วยเป็นมิตรขึ้นเล็กน้อย:

    $command = array( get_class($this->target), $method );
    /* -- snip -- */
    $this->acl->isAllowed( $this->target->getPermissions(), $command )
    

วิดีโอคู่ที่อาจช่วยให้คุณสามารถใช้งานได้เอง:

บันทึกด้านข้าง

ดูเหมือนคุณจะมีความเข้าใจที่ค่อนข้างบ่อย (และผิดอย่างสิ้นเชิง) ว่า Model ใน MVC คืออะไร รุ่นไม่ได้เป็นชั้นเรียน หากคุณตั้งชื่อคลาสFooBarModelหรือสิ่งที่สืบทอดมาแสดงว่าAbstractModelคุณทำผิด

ใน MVC ที่เหมาะสม Model คือเลเยอร์ซึ่งมีคลาสมากมาย ส่วนใหญ่ของชั้นเรียนสามารถแบ่งออกเป็นสองกลุ่มตามความรับผิดชอบ:

- ลอจิกธุรกิจโดเมน

( อ่านเพิ่มเติม : ที่นี่และที่นี่ ):

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

วัตถุธุรกิจโดเมนไม่ขึ้นอยู่กับฐานข้อมูล เมื่อคุณสร้างใบแจ้งหนี้ไม่สำคัญว่าข้อมูลจะมาจากที่ใด อาจเป็นได้ทั้งจาก SQL หรือจาก REST API ระยะไกลหรือแม้แต่ภาพหน้าจอของเอกสาร MSWord ตรรกะทางธุรกิจไม่เปลี่ยนแปลง

- การเข้าถึงและจัดเก็บข้อมูล

อินสแตนซ์ที่สร้างจากคลาสกลุ่มนี้บางครั้งเรียกว่า Data Access Objects โดยปกติโครงสร้างที่ใช้รูปแบบData Mapper (อย่าสับสนกับ ORM ที่มีชื่อเดียวกัน .. ไม่มีความสัมพันธ์) นี่คือที่ที่คำสั่ง SQL ของคุณจะเป็น (หรืออาจจะเป็น DomDocument ของคุณเนื่องจากคุณเก็บไว้ใน XML)

นอกเหนือจากสองส่วนหลักแล้วยังมีกลุ่มอินสแตนซ์ / คลาสอีกหนึ่งกลุ่มที่ควรกล่าวถึง:

- บริการ

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

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

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

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


34
ฉันเพิ่งเรียนรู้เพิ่มเติมใน 5 นาทีในการอ่านซ้ำสิ่งนี้มากกว่าที่ฉันมีในหลายเดือน คุณเห็นด้วยกับ: ตัวควบคุมแบบบางส่งไปยังบริการที่รวบรวมข้อมูลมุมมองหรือไม่? นอกจากนี้หากคุณเคยตอบคำถามโดยตรงโปรดส่งข้อความถึงฉัน
Stephane

2
ฉันเห็นด้วยบางส่วน การรวบรวมข้อมูลจากมุมมองเกิดขึ้นภายนอก MVC triad เมื่อคุณเริ่มต้นRequestอินสแตนซ์ (หรืออะนาล็อกบางส่วน) ตัวควบคุมจะดึงข้อมูลจากRequestอินสแตนซ์เท่านั้นและส่งต่อข้อมูลส่วนใหญ่ไปยังบริการที่เหมาะสม (บางส่วนไปดูด้วย) บริการดำเนินการตามที่คุณสั่งให้ทำ จากนั้นเมื่อมุมมองสร้างการตอบกลับจะร้องขอข้อมูลจากบริการและจากข้อมูลนั้นจะสร้างการตอบสนอง การตอบกลับดังกล่าวอาจเป็น HTML ที่สร้างจากเทมเพลตหลายแบบหรือเพียงแค่ส่วนหัวตำแหน่ง HTTP ขึ้นอยู่กับสถานะที่กำหนดโดยคอนโทรลเลอร์
tereško

4
ในการใช้คำอธิบายแบบง่าย: คอนโทรลเลอร์ "เขียน" ไปยังโมเดลและมุมมองให้ดู "อ่าน" จากโมเดล เลเยอร์โมเดลเป็นโครงสร้างแฝงในรูปแบบที่เกี่ยวข้องกับเว็บทั้งหมดที่ได้รับแรงบันดาลใจจาก MVC
tereško

@Stephane สำหรับการถามคำถามโดยตรงคุณสามารถส่งข้อความถึงฉันใน Twitter ได้ตลอดเวลา หรือคุณเคยตั้งคำถามว่า "แบบยาว" ที่ไม่สามารถอัดเป็น 140 ตัวอักษรได้?
tereško

อ่านจากโมเดล: นั่นหมายถึงบทบาทที่กระตือรือร้นของนางแบบหรือไม่? ฉันไม่เคยได้ยินมาก่อน ฉันสามารถส่งลิงค์ให้คุณผ่านทาง twitter ได้ตลอดเวลาหากคุณต้องการ อย่างที่คุณเห็นคำตอบเหล่านี้กลายเป็นการสนทนาอย่างรวดเร็วและฉันพยายามให้ความเคารพต่อไซต์นี้และผู้ติดตาม Twitter ของคุณ
Stephane

16

ACL และคอนโทรลเลอร์

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

tereškoได้อธิบายถึงวิธีที่คุณสามารถแยกสิ่งนี้ได้มากขึ้นด้วยรูปแบบมัณฑนากร

ฉันจะย้อนกลับไปหนึ่งก้าวก่อนเพื่อค้นหาปัญหาเดิมที่คุณกำลังเผชิญอยู่และพูดคุยกันสักหน่อย

ในแง่หนึ่งคุณต้องการมีคอนโทรลเลอร์ที่ทำงานตามคำสั่ง (คำสั่งหรือการกระทำเรียกว่าคำสั่ง)

ในทางกลับกันคุณต้องการให้สามารถใส่ ACL ในแอปพลิเคชันของคุณได้ สาขาการทำงานของ 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 ในกรณีของคุณควบคุมการเข้าถึงคำสั่งไม่ใช่คำสั่งเอง


สองคำถาม: CommandNotFoundResponse & CommandNotAllowedResponse: คุณจะส่งสิ่งเหล่านี้จากคลาส ACL ไปยังเราเตอร์หรือคอนโทรลเลอร์และคาดหวังการตอบสนองแบบสากลหรือไม่? 2: หากคุณต้องการรวม method + attributes คุณจะจัดการอย่างไร?
Stephane

1: การตอบสนองคือการตอบสนองที่นี่ไม่ใช่จาก ACL แต่มาจากเราเตอร์ ACL ช่วยเราเตอร์ในการค้นหาประเภทการตอบสนอง (ไม่พบโดยเฉพาะอย่างยิ่ง: ห้าม) 2: ขึ้นอยู่กับ หากคุณหมายถึงแอตทริบิวต์เป็นพารามิเตอร์จากการกระทำและคุณต้องการ ACL'ing พร้อมพารามิเตอร์ให้วางไว้ใน ACL
hakre

13

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

นอกจากนี้คุณยังสามารถทำอัพสตรีมได้มากขึ้นในผู้มอบหมายงาน (หากแอปพลิเคชันของคุณมีจริง) และค้นหาสิทธิ์ตาม URL แทนวิธีการควบคุม

แก้ไข : ไม่ว่าคุณจะต้องการเข้าถึงฐานข้อมูลเซิร์ฟเวอร์ LDAP และอื่น ๆ จะตั้งฉากกับคำถาม ประเด็นของฉันคือคุณสามารถใช้การอนุญาตตาม URL แทนวิธีการควบคุม สิ่งเหล่านี้มีประสิทธิภาพมากขึ้นเนื่องจากโดยทั่วไปแล้วคุณจะไม่เปลี่ยน URL ของคุณ (ส่วนติดต่อสาธารณะประเภทพื้นที่ URL) แต่คุณอาจเปลี่ยนการใช้งานตัวควบคุมของคุณได้เช่นกัน

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


โปรดอัปเดตคำตอบของคุณและเพิ่มรายละเอียดเกี่ยวกับ Dispatcher ฉันมีผู้มอบหมายงาน - ตรวจพบวิธีการของคอนโทรลเลอร์ที่ฉันควรเรียกโดยใช้ URL แต่ฉันไม่เข้าใจว่าฉันจะรับบทบาทได้อย่างไร (ฉันต้องเข้าถึง DB จึงจะทำได้) ใน Dispatcher หวังว่าจะได้ยินคุณเร็ว ๆ นี้
Kirzilla

Aha มีความคิดของคุณ ฉันควรตัดสินใจอนุญาตให้ดำเนินการหรือไม่โดยไม่ต้องเข้าถึงวิธีการ! ยกนิ้วให้! คำถามสุดท้ายที่ยังไม่ได้รับการแก้ไข - วิธีเข้าถึงโมเดลจาก Acl ความคิดใด ๆ ?
Kirzilla

@ Kirzilla ฉันมีปัญหาเดียวกันกับตัวควบคุม ดูเหมือนว่าการพึ่งพาจะต้องมีอยู่ที่ไหนสักแห่ง แม้ว่า ACL จะไม่ใช่เลเยอร์โมเดลล่ะ? คุณจะป้องกันไม่ให้เป็นที่พึ่งพาได้อย่างไร?
Stephane
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.