programing

웹 MVC 응용 프로그램에 액세스 제어 목록을 구현하려면 어떻게 해야 합니까?

sourcejob 2022. 11. 5. 17:32
반응형

웹 MVC 응용 프로그램에 액세스 제어 목록을 구현하려면 어떻게 해야 합니까?

첫 번째 질문

MVC에서 ACL을 얼마나 간단하게 구현할 수 있는지 설명해 주시겠습니까?

다음으로 컨트롤러에서 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 코드를 추가해야 하지만 더 이상의 종속성은 필요하지 않습니다.

다음 접근법은 모든 컨트롤러의 방식을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!");
    ...   
  }

}
?>

이전 코드보다 나아졌지만 주요 단점은...

  • 모든 컨트롤러의 메서드는 비공개여야 합니다.
  • 각 컨트롤러의 __call 메서드에 ACL 코드를 추가해야 합니다.

다음 접근법은 ACL 코드를 부모 컨트롤러에 넣는 것이지만 모든 자녀 컨트롤러의 메서드는 비공개로 유지해야 합니다.

해결책은 무엇일까?그리고 베스트 프랙티스는 무엇일까요?ACL 함수를 호출하여 메서드의 실행 허용 여부를 결정해야 합니다.

두 번째 질문

두 번째 질문은 ACL을 사용하여 역할을 얻는 것입니다.게스트, 사용자 및 사용자의 친구가 있다고 가정해 보겠습니다.사용자는 친구만 볼 수 있는 자신의 프로필을 볼 수 있는 액세스를 제한했습니다.모든 게스트가 이 사용자의 프로필을 볼 수 없습니다.자, 여기 논리가 있습니다.

  • 호출된 메서드가 프로파일인지 확인해야 합니다.
  • 이 프로파일의 주인을 찾아내야 합니다
  • 뷰어가 이 프로파일의 소유자인지 아닌지를 검출해야 합니다.
  • 이 프로파일에 대한 제한 규칙을 읽어야 합니다.
  • 프로파일 방식의 실행 여부를 결정해야 합니다.

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

첫 번째 부품/답변(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에 준거한다.
    • permission denied(권한 거부)가 표시되면 컨트롤러 내에서 잠겨 있지 않습니다.더 많은 옵션
  3. 보안 인스턴스를 다른 개체에 주입할 수 있습니다. 그러면 보호 상태가 유지됩니다.
  4. 잊어버리다당신은 그것이 원래 물건인 척 할 수 있고, 그것은 똑같이 반응할 것이다.

, 이 메서드에도 큰 문제가 있습니다.즉, 시큐어 오브젝트의 실장 및 인터페이스(기존 메서드의 검색에도 적용)가 네이티브로 설정되어 있는지, 또는 상속 체인의 일부인지를 확인할 수 없습니다.

두 번째 부분/답변(개체의 RBAC)

이 경우 도메인 오브젝트(예:Profile) 자체에는 소유자에 대한 자세한 내용이 포함되어 있습니다.즉, 사용자가 액세스 권한이 있는지(및 어느 수준에서) 확인하려면 다음 행을 변경해야 합니다.

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

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

  • ACL에 문제의 오브젝트를 지정합니다.하지만 디메터의 법칙을 위반하지 않도록 주의해야 합니다.

    $this->acl->isAllowed( get_class($this->target), $method )
    
  • 관련된 모든 세부사항을 요청하고 필요한 것만 ACL에 제공합니다.이것에 의해, 유닛 테스트의 편리성도 향상됩니다.

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

독자적인 실장 방법에 도움이 되는 비디오를 몇 개 소개합니다.

사이드 노트

MVC의 모델이 무엇인지에 대한 일반적인 이해(완전히 잘못된)가 있는 것 같습니다.모델은 클래스가 아닙니다.라는 이름의 클래스가 있는 경우FooBarModel또는 상속받는 것AbstractModel잘못하고 있는 거야

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

- 도메인 비즈니스 로직

(자세한 내용이쪽이쪽):

이 클래스 그룹의 인스턴스는 가치 계산, 다른 조건 확인, 판매 규칙 구현 및 기타 모든 작업을 수행합니다.이러한 작업은 "비즈니스 로직"이라고 합니다.데이터가 어떻게 저장되는지, 어디에 저장되는지, 심지어 스토리지가 존재하는지조차 알 수 없습니다.

Domain Business 개체는 데이터베이스에 종속되지 않습니다.청구서를 작성할 때는 데이터의 출처는 중요하지 않습니다.SQL 또는 원격 REST API 또는 MSWord 문서의 스크린샷을 사용할 수 있습니다.비즈니스 로직은 변경되지 않습니다.

- 데이터 액세스스토리지

이 클래스 그룹에서 생성된 인스턴스를 데이터 액세스 개체라고 부르기도 합니다.보통 데이터 매퍼 패턴을 구현하는 구조(같은 이름의 ORM과 혼동하지 않음)no relations )를 선택합니다.SQL 문(또는 XML에 저장하기 때문에 DominoDocument)이 있을 수 있습니다.

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

- 서비스

여기서 고객님의 컴포넌트와 서드파티 컴포넌트가 사용됩니다.예를 들어, "인증"을 서비스라고 생각할 수 있습니다.서비스나 외부 코드로 제공할 수 있습니다.또, 「메일 송신자」는, PHMailer, Swift Mailer, 또는 자신의 메일 송신자 컴포넌트와 도메인 오브젝트를 결합하는 서비스입니다.

또 다른 서비스 소스는 도메인 및 데이터 액세스 계층에 대한 추상화입니다.컨트롤러가 사용하는 코드를 단순화하기 위해 작성됩니다.예를 들어: 새 사용자 계정을 만들려면 여러 도메인 개체 및 매퍼를 사용해야 할 수 있습니다.단, 서비스를 사용함으로써 컨트롤러에 필요한 회선은 1~2개뿐입니다.

서비스를 만들 때 주의해야 할 것은 전체 레이어가 얇아야 한다는 것입니다.서비스에는 비즈니스 로직이 없습니다.도메인 오브젝트, 컴포넌트 및 매핑을 조정하기 위해서만 존재합니다.

이들 서비스의 공통점 중 하나는 서비스가 View레이어에 직접적인 영향을 주지 않고 MVC 구조체 외부에서 사용할 수 있는(및 자주 종료되는) 정도로 자율적이라는 것입니다.또한 이러한 자체 관리 구조를 통해 서비스와 나머지 애플리케이션 간의 결합이 매우 낮기 때문에 다른 프레임워크/아키텍처로의 이행을 훨씬 쉽게 할 수 있습니다.

ACL 및 컨트롤러

우선:이것들은 가장 빈번하게 다른 물건/층입니다.모범적인 컨트롤러 코드를 비판할 때 두 코드를 합친다는 것은 명백하게 너무 빡빡하다는 것입니다.

Tereshko는 이미 이것을 데코레이터 패턴과 더 잘 결합할 수 있는 방법을 개략적으로 설명하고 있습니다.

먼저 한 걸음 물러서서 당신이 직면하고 있는 원래의 문제를 찾고 그 때 그것에 대해 조금 논의하겠습니다.

한편으로 명령된 작업(명령 또는 액션, 명령이라고 부릅시다)만 수행하는 컨트롤러가 필요합니다.

한편, 애플리케이션에 ACL 를 넣을 수 있도록 하고 싶다고 생각하고 있습니다.이러한 ACL 의 작업 분야는, 질문을 올바르게 이해하고 있는 경우는, 애플리케이션의 특정의 커맨드에의 액세스를 제어하는 것입니다.

따라서 이런 종류의 접근컨트롤에는 이 두 가지를 하나로 묶을 수 있는 다른 것이 필요합니다.커맨드가 실행되는 콘텍스트에 근거해, ACL 가 기동해, 특정의 커맨드를 특정의 서브젝트(예를 들면 유저)에 의해서 실행할 수 있는지 아닌지를 판단할 필요가 있습니다.

지금까지의 내용을 정리합니다.

  • 명령어
  • ACL
  • 사용자

ACL 컴포넌트는 다음과 같습니다.적어도 명령어에 대해 알아야 하며(정확한 명령어를 식별해야 함) 사용자를 식별할 수 있어야 합니다.사용자는 보통 고유 ID로 쉽게 식별할 수 있습니다.그러나 웹 애플리케이션에는 전혀 식별되지 않는 사용자(게스트, 익명, everyone 등)가 있는 경우가 많습니다.이 예에서는 ACL이 사용자 개체를 소비하고 이러한 세부사항을 캡슐화할 수 있다고 가정합니다.사용자 객체는 응용 프로그램 요청 객체에 바인딩되어 ACL이 이를 소비할 수 있습니다.

명령어를 특정하는 것은 어떻습니까?MVC 패턴을 해석하면 명령어는 클래스 이름과 메서드 이름이 복합되어 있음을 알 수 있습니다.자세히 살펴보면 명령어에 대한 인수(파라미터)도 있습니다.그럼 정확히 어떤 명령어를 식별하는지 물어봐도 될까요?클래스 이름, 메서드 이름, 인수 수 또는 이름, 심지어 인수 안에 있는 데이터 또는 이 모든 것의 혼합?

ACL에서 명령어를 식별하기 위해 필요한 상세 수준에 따라 크게 달라질 수 있습니다.이 예에서는 명령어가 클래스 이름과 메서드 이름으로 식별되도록 단순하게 유지하겠습니다.

따라서 이 세 부분(ACL, Command 및 User)이 서로 어떻게 속해 있는지 더욱 명확하게 알 수 있습니다.

예를 들어 가상 ACL을 사용하면 다음 작업을 이미 수행할 수 있습니다.

$acl->commandAllowedForUser($command, $user);

여기서 무슨 일이 일어나고 있는지 확인해 주세요.명령어와 사용자를 모두 식별할 수 있도록 함으로써 ACL이 기능을 합니다.ACL 의 작업은, 유저 오브젝트와 concrete 커맨드의 양쪽 모두의 작업과는 관계가 없습니다.

한 부분만 빠졌는데, 이건 공중에서 살 수 없어요.그리고 그렇지 않다.그래서 당신은 접근 제어가 필요한 장소를 찾아야 합니다.표준 웹 어플리케이션에서 어떤 일이 일어나는지 살펴보겠습니다.

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

이 장소를 찾으려면 구체적인 명령어가 실행되기 전이어야 하므로 목록을 줄이고 다음 (잠재적인) 장소만 조사하면 됩니다.

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

응용 프로그램의 어느 시점에서 특정 사용자가 구체적인 명령을 수행하도록 요청했음을 알 수 있습니다.이미 ACL을 실행하고 있습니다.사용자가 존재하지 않는 명령어를 요구할 경우 해당 명령어를 실행할 수 없습니다.따라서 응용 프로그램에서 발생하는 모든 경우 "실제" ACL 체크를 추가하는 것이 좋습니다.

명령어가 검출되어 ACL이 처리할 수 있도록 명령어의 ID를 작성할 수 있습니다.사용자가 명령어를 사용할 수 없는 경우 명령어는 실행되지 않습니다(액션).아마CommandNotAllowedResponse대신CommandNotFoundResponse구체적인 명령어로 요청을 해결할 수 없는 경우.

구체적인 HTTPRequest의 매핑이 명령어에 매핑되는 장소는 종종 라우팅이라고 불립니다.라우팅에는 이미 명령어를 찾는 작업이 있기 때문에 ACL별로 명령어가 실제로 허용되는지 여부를 확인하기 위해 확장하면 어떨까요?예를 들어,RouterACL 대응 라우터에 대해서:RouterACL라우터가 아직 인식되지 않은 경우User, 그 다음에RouterACL이 기능하려면 명령어뿐만 아니라 사용자도 식별해야 하기 때문에 올바른 위치가 아닙니다.이 장소는 다양할 수 있지만 확장해야 할 장소를 쉽게 찾을 수 있습니다.사용자와 명령어 요건을 채우는 장소이기 때문입니다.

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

사용자는 처음부터 사용할 수 있습니다.명령어를 먼저 사용합니다.Request(Command).

따라서 ACL 체크를 각 명령어의 구체적인 구현 내부에 배치하는 대신 그 앞에 배치해야 합니다.무거운 패턴이나 마법 같은 것은 필요 없습니다.ACL은 그 기능을 하고, 사용자는 그 기능을 하며, 특히 명령어는 그 기능을 수행합니다.명령어만 하면 됩니다.이 명령어는 역할이 자신에게 적용되는지, 어딘가에서 보호되고 있는지 여부를 알 필요가 없습니다.

그러니까 서로 소유하지 않는 것들은 따로 떼어놓으세요.Single Responsibility Principle(SRP; 단일 책임 원칙)의 약간 다른 표현을 사용합니다.명령어가 변경되었기 때문에 명령어를 변경해야 하는 이유는 1개뿐입니다.애플리케이션에 ACL을 도입했기 때문이 아닙니다.사용자 개체를 전환하기 때문이 아닙니다.HTTP/HTML 인터페이스에서SOAP 또는 명령줄 인터페이스로 이행하기 때문이 아닙니다.

이 경우 ACL은 명령어에 대한 액세스를 제어합니다.명령어 자체는 제어하지 않습니다.

한 가지 방법은 모든 컨트롤러를 다른 클래스로 래핑하여 컨트롤러를 확장한 후 모든 함수 호출을 래핑된 인스턴스에 위임하는 것입니다.

또한 제어 방식이 아닌 디스패처(어플리케이션에 실제로 권한이 있는 경우)에서 더 업스트림에서 권한을 수행하고 URL에 따라 권한을 검색할 수도 있습니다.

edit: 데이터베이스, LDAP 서버 등에 액세스할 필요가 있는지 여부는 질문에 직교합니다.제 요점은 컨트롤러 방식 대신 URL을 기반으로 인증을 구현할 수 있다는 것입니다.일반적으로 URL(퍼블릭인터페이스의 URL 영역)을 변경하지 않지만 컨트롤러의 구현을 변경하는 것이 좋습니다.

일반적으로 특정 URL 패턴을 특정 인증 방식 및 인가 지시에 매핑하는 컨피규레이션파일이 1개 또는 여러 개 있습니다.디스패처는 요구를 컨트롤러에 디스패치하기 전에 사용자에게 권한이 있는지 여부를 판단하고 권한이 없는 경우 디스패치를 중단합니다.

언급URL : https://stackoverflow.com/questions/3430181/how-can-i-implement-an-access-control-list-in-my-web-mvc-application

반응형