복붙노트

웹 MVC 애플리케이션에 액세스 제어 목록을 구현하려면 어떻게해야합니까?

PHP

웹 MVC 애플리케이션에 액세스 제어 목록을 구현하려면 어떻게해야합니까?

첫 번째 질문

제발, 내가 얼마나 간단한 ACL을 MVC에서 구현할 수 있는지 설명해 주시겠습니까?

컨트롤러에 Acl을 사용하는 첫 번째 방법은 다음과 같습니다.

<?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 코드를 추가해야하지만, 더 이상 의존성이 필요하지 않습니다.

다음 접근법은 모든 컨트롤러의 메소드를 비공개로 만들고 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 코드를 삽입하는 것이지만 모든 하위 컨트롤러의 메소드를 비공개로 유지해야합니다.

해결 방안은 무엇인가? 가장 좋은 방법은 무엇입니까? 어디에서 Acl 함수를 호출하여 허용되거나 허용되지 않는 메소드가 실행되는지 결정해야합니다.

두 번째 질문

두 번째 질문은 Acl을 사용하는 역할에 관한 것입니다. 손님, 사용자 및 사용자의 친구가 있다고 상상해 봅시다. 사용자는 친구 만 볼 수있는 프로필보기에 대한 액세스를 제한합니다. 모든 참석자가이 사용자의 프로필을 볼 수 없습니다. 그래서 여기 논리가 있습니다 ..

주요 질문은 프로필 소유자를 찾는 것입니다. 모델의 메소드 $ model-> getOwner ()를 실행하는 프로파일의 소유자는 누구인지 알 수 있지만 Acl은 모델에 액세스 할 수 없습니다. 어떻게 구현할 수 있습니까?

내 생각이 분명하기를 바랍니다. 미안해, 내 영어로.

고맙습니다.

해결법

  1. ==============================

    1.나의 겸허 한 견해로는, 이것을 접근하는 가장 좋은 방법은 데코레이터 패턴을 사용하는 것입니다. 기본적으로 이것은 당신이 당신의 물건을 가져 와서 다른 물건 안에 넣는 것을 의미합니다. 그것은 보호용 껍질처럼 행동 할 것입니다. 이렇게하면 원래 클래스를 확장 할 필요가 없습니다. 다음은 그 예입니다.

    나의 겸허 한 견해로는, 이것을 접근하는 가장 좋은 방법은 데코레이터 패턴을 사용하는 것입니다. 기본적으로 이것은 당신이 당신의 물건을 가져 와서 다른 물건 안에 넣는 것을 의미합니다. 그것은 보호용 껍질처럼 행동 할 것입니다. 이렇게하면 원래 클래스를 확장 할 필요가 없습니다. 다음은 그 예입니다.

    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();
    

    이 솔루션에는 몇 가지 장점이 있습니다.

    그러나이 방법에는 중요한 문제가 하나 있습니다. 즉, 보안 개체 구현 및 인터페이스 (기존 메서드를 찾는 데에도 적용됩니다) 또는 일부 상속 체인의 일부인지 여부를 기본적으로 확인할 수 없습니다.

    이 경우 인식해야 할 주요 차이점은 도메인 객체 (예 : 프로필) 자체에 소유자에 대한 세부 정보가 포함되어 있다는 것입니다. 즉, 사용자가 액세스 할 수있는 경우 (그리고 어떤 수준에서) 액세스 할 수 있는지를 확인하려면이 행을 변경해야합니다.

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

    기본적으로 두 가지 옵션이 있습니다.

    자신 만의 구현을 도출 할 수있는 몇 가지 비디오 :

    당신은 MVC의 어떤 모델인지에 대한 아주 일반적인 (그리고 완전히 잘못된) 이해가있는 것 같습니다. 모델은 클래스가 아닙니다. FooBarModel이라는 클래스가 있거나 AbstractModel을 상속받은 클래스가 있다면 잘못 처리하고있는 것입니다.

    적절한 MVC에서 Model은 많은 클래스를 포함하는 레이어입니다. 수업의 상당 부분은 책임에 따라 두 그룹으로 나눌 수 있습니다.

    (더 읽기 : 여기와 여기) :

    이 클래스 그룹의 인스턴스는 값 계산, 다른 조건 확인, 판매 규칙 구현 및 나머지 작업을 모두 "비즈니스 로직"이라고합니다. 그들은 데이터가 저장되는 방법, 저장되는 위치 또는 저장소가 처음 존재하는 경우에도 단서를 가지고 있지 않습니다.

    도메인 비즈니스 개체는 데이터베이스에 의존하지 않습니다. 송장을 생성 할 때 데이터가 어디에서 왔는지는 중요하지 않습니다. SQL 또는 원격 REST API 또는 MSWord 문서의 스크린 샷 일 수 있습니다. 비즈니스 로직은 변경되지 않습니다.

    이 클래스 그룹에서 만든 인스턴스를 데이터 액세스 개체라고도합니다. 일반적으로 Data Mapper 패턴을 구현하는 구조체 (같은 이름의 ORM과는 관계가 없습니다). 여기가 SQL 문 (또는 XML로 저장하기 때문에 DomDocument 일 수도 있습니다)입니다.

    두 가지 주요 부분 이외에도 언급해야 할 인스턴스 / 클래스 그룹이 하나 더 있습니다.

    여기에서 귀하와 제 3 자 구성 요소가 사용됩니다. 예를 들어, "인증"은 사용자 자신 또는 일부 외부 코드에서 제공 할 수있는 서비스로 생각할 수 있습니다. 또한 "메일 발신자"는 일부 도메인 객체를 PHPMailer 또는 SwiftMailer 또는 메일 발신자 구성 요소와 결합시킬 수있는 서비스입니다.

    또 다른 서비스 소스는 도메인 및 데이터 액세스 레이어에 대한 추상화입니다. 컨트롤러로 사용되는 코드를 단순화하기 위해 만들어졌습니다. 예를 들어, 새 사용자 계정을 만들려면 여러 도메인 객체와 매퍼로 작업해야 할 수 있습니다. 하지만 서비스를 사용하면 컨트롤러에 한두 줄만 있으면됩니다.

    서비스를 만들 때 기억해야 할 점은 전체 레이어가 얇은 것으로 가정된다는 것입니다. 서비스에는 비즈니스 로직이 없습니다. 도메인 객체, 구성 요소 및 매퍼를 둘러싼 다.

    그들 모두 공통점이있는 것들 중 하나는 서비스가 직접적인 방법으로 View 레이어에 영향을 미치지 않으며, MVC 구조 자체 외부에서 사용될 수 있고 (종종 종료되는) 그러한 정도까지는 자율적이다는 것입니다. 또한 이러한 자체 유지 구조는 서비스와 나머지 응용 프로그램 간의 결합이 매우 낮기 때문에 다른 프레임 워크 / 아키텍처로의 마이그레이션을 훨씬 쉽게 만듭니다.

  2. ==============================

    2.무엇보다도 : 이들은 가장 다른 것들 / 레이어입니다. 모범적 인 컨트롤러 코드를 비판하면서, 두 컨트롤러를 모으는 것은 - 분명히 너무 빡빡합니다.

    무엇보다도 : 이들은 가장 다른 것들 / 레이어입니다. 모범적 인 컨트롤러 코드를 비판하면서, 두 컨트롤러를 모으는 것은 - 분명히 너무 빡빡합니다.

    tereško는 이미 데코레이터 패턴으로 이것을 더 잘 분리 할 수있는 방법을 설명했습니다.

    나는 당신이 직면하고있는 최초의 문제를 찾아 먼저 논의하기 위해 한 발 뒤로 물러서 라.

    한편으로는 명령받은 작업을 수행하는 컨트롤러가 필요합니다 (명령 또는 동작, 명령이라고 부름).

    반면에 ACL을 응용 프로그램에 넣을 수 있기를 원합니다. 이러한 ACL의 작업 영역은 - 귀하의 질문을 올바르게 이해 한 경우 - 귀하의 응용 프로그램의 특정 명령에 대한 액세스를 제어해야합니다.

    따라서 이러한 종류의 액세스 제어는이 두 가지를 하나로 모으는 다른 것을 필요로합니다. 명령이 실행되는 컨텍스트를 기반으로 ACL이 시작되고 특정 명령 (예 : 사용자)이 특정 명령을 실행할 수 있는지 여부를 결정해야합니다.

    여기에 우리가 가진 것을 요약 해 보겠습니다.

    ACL 구성 요소는 여기에 있습니다 : 명령에 대해 (명령을 정확하게 식별하기 위해) 적어도 알 필요가 있으며 사용자를 식별 할 수 있어야합니다. 사용자는 대개 고유 한 ID로 쉽게 식별됩니다. 그러나 종종 웹 응용 프로그램에는 전혀 식별되지 않은 사용자가 있습니다. 게스트, 익명, 모든 사람 등이 있습니다.이 예에서는 ACL이 사용자 개체를 소비하고 이러한 정보를 멀리 캡슐화 할 수 있다고 가정합니다. 사용자 개체는 응용 프로그램 요청 개체에 바인딩되며 ACL은이를 소비 할 수 있습니다.

    명령을 식별하는 것은 어떻습니까? MVC 패턴에 대한 해석은 명령이 클래스 이름과 메소드 이름의 합성임을 시사합니다. 좀 더 자세히 살펴보면 명령에 대한 인수 (매개 변수)도 있습니다. 따라서 명령을 정확히 식별하는 것은 무엇입니까? 클래스 명, 메소드 명, 인수의 수 또는 이름, 인수 내의 데이터조차 또는이 모든 것의 혼합?

    ACL에서 명령을 식별 할 필요가있는 세부 사항 레벨에 따라 이것은 많이 다를 수 있습니다. 예를 들어 간단하게 유지하고 명령이 클래스 이름과 메소드 이름으로 식별되도록 지정하십시오.

    따라서이 세 부분 (ACL, 명령 및 사용자)이 서로 어떻게 관련되어 있는지에 대한 컨텍스트가보다 명확 해졌습니다.

    상상의 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 검사를 추가하는 것이 좋습니다.

    명령이 위치하고 있으므로 ACL에서 ACL을 처리 할 수 ​​있도록 명령의 ID를 만들 수 있습니다. 명령이 사용자에게 허용되지 않으면 명령이 실행되지 않습니다 (조치). 요청이 구체적인 명령으로 해결 될 수없는 경우 CommandNotFoundResponse 대신 CommandNotAllowedResponse가있을 수 있습니다.

    구체적인 HTTP 요청의 매핑이 명령에 매핑되는 곳을 종종 라우팅이라고합니다. 라우팅에 명령을 찾기위한 작업이 이미 있으므로 명령을 실제로 ACL 당 허용되는지 확인하기 위해 확장하지 않는 이유는 무엇입니까? 예 : 라우터를 ACL 인식 라우터 인 RouterACL로 확장합니다. 라우터가 사용자를 아직 모르는 경우 라우터가 올바른 위치가 아닙니다. ACL이 명령을 작동 할뿐만 아니라 사용자를 식별해야하기 때문입니다. 따라서이 장소는 다양 할 수 있지만 확장해야 할 장소를 쉽게 찾을 수 있습니다. 사용자 및 명령 요구 사항을 모두 채우는 장소이기 때문에 쉽게 찾을 수 있습니다.

    User -> Browser -> Request (HTTP)
       -> Request (Command)
    

    사용자는 처음부터 사용 가능합니다. 명령은 먼저 요청 (명령)을 사용합니다.

    따라서 각 명령의 구체적인 구현 내에서 ACL 검사를 수행하는 대신 미리 배치해야합니다. 당신은 무거운 패턴이나 마법 같은 것이 필요하지 않습니다. ACL은 일을합니다. 사용자는 그 일을합니다. 특히 명령은 일을합니다. 명령뿐입니다. 이 명령은 어딘가에 지키고 있는지 여부에 상관없이 역할이 적용되는지 여부를 알지 못한다.

    서로를 속박하지 말라. SRP (Single Responsibility Principle)를 약간 재 인용하십시오. 명령이 변경 되었기 때문에 명령을 변경할 수있는 유일한 이유가 있어야합니다. 이제는 응용 프로그램에 ACL 기능을 도입했기 때문에가 아닙니다. User 개체를 전환했기 때문에가 아닙니다. HTTP / HTML 인터페이스에서 SOAP 또는 명령 줄 인터페이스로 마이그레이션하기 때문에가 아닙니다.

    귀하의 경우 ACL은 명령 자체가 아닌 명령에 대한 액세스를 제어합니다.

  3. ==============================

    3.한 가지 가능성은 컨트롤러를 확장하는 다른 클래스에 모든 컨트롤러를 래핑하고 권한을 확인한 후 랩된 인스턴스에 모든 함수 호출을 위임하도록하는 것입니다.

    한 가지 가능성은 컨트롤러를 확장하는 다른 클래스에 모든 컨트롤러를 래핑하고 권한을 확인한 후 랩된 인스턴스에 모든 함수 호출을 위임하도록하는 것입니다.

    또한 디스패처 (응용 프로그램에 실제로 포함되어있는 경우)에서 제어 방법 대신 URL을 기반으로 권한을 조회하면 더 많은 업스트림을 수행 할 수 있습니다.

    편집 : 데이터베이스, LDAP 서버 등에 액세스해야하는지 여부는 질문과 직각을 이룹니다. 요점은 컨트롤러 메소드 대신 URL을 기반으로 권한을 구현할 수 있다는 것이 었습니다. 일반적으로 URL (공용 영역의 URL 영역)을 변경하지 않으므로 더 강력하지만 컨트롤러의 구현을 변경할 수도 있습니다.

    일반적으로 특정 URL 패턴을 특정 인증 방법 및 권한 부여 지시문에 매핑하는 하나 이상의 구성 파일이 있습니다. 디스패처는 컨트롤러에 요청을 보내기 전에 사용자가 승인되었는지 여부를 결정하고 그렇지 않은 경우 디스패치를 ​​중단합니다.

  4. from https://stackoverflow.com/questions/3430181/how-can-i-implement-an-access-control-list-in-my-web-mvc-application by cc-by-sa and MIT license