문제

CakePHP에서 ACL을 구현하는 데 어려움을 겪고 있습니다.설명서를 읽어본 후 케이크 매뉴얼 다른 여러 튜토리얼, 블로그 게시물 등에서 많은 공백을 메우는 데 도움이 된 Aran Johnson의 훌륭한 튜토리얼을 찾았습니다.그의 예는 몇 군데, 특히 그가 사용하는 ARO 트리 구조에서 본 다른 예와 충돌하는 것 같습니다.

그의 그의 사용자 그룹은 계단식 트리로 설정됩니다. 가장 일반적인 사용자 유형은 트리의 맨 위에 있고 그 하위 그룹은 더 제한된 액세스 유형으로 분기됩니다.다른 곳에서는 일반적으로 각 사용자 유형을 동일한 일반 사용자 유형의 하위 항목으로 보았습니다.

CakePHP에서 ARO와 ACO를 어떻게 설정합니까?모든 팁에 감사드립니다!

도움이 되었습니까?

해결책

CakePHP에 내장된 ACL 시스템은 정말 강력하지만 실제 구현 세부 사항에 대해서는 제대로 문서화되어 있지 않습니다.여러 CakePHP 기반 프로젝트에서 어느 정도 성공을 거둔 시스템은 다음과 같습니다.

이는 기존의 일부 그룹 수준 액세스 시스템을 수정한 것입니다. 다른 곳에서 문서화됨.우리 시스템의 목표는 사용자에게 그룹 수준에서 권한을 부여하지만 자신이 만든 항목에 대해 또는 사용자별로 특정 추가 권한을 가질 수 있는 간단한 시스템을 갖는 것입니다.우리는 aros_acos 테이블.

Users 테이블과 Roles 테이블이 있습니다.

사용자

user_id, user_name, role_id

역할

id, role_name

각 역할에 대한 ARO 트리를 만듭니다(일반적으로 무단 게스트(id 1), 승인된 사용자(id 2), 사이트 중재자(id 3) 및 관리자(id 4))의 4가지 역할이 있습니다.

cake acl create aro / Role.1

cake acl create aro 1 Role.2 ... etc ...

그런 다음 케이크 명령줄 도구에서는 이를 수행하지 않으므로 SQL이나 phpMyAdmin 또는 이와 유사한 것을 사용하여 이들 모두에 대한 별칭을 추가해야 합니다.우리는 모두 'Role-{id}' 및 'User-{id}'를 사용합니다.

그런 다음 ROOT ACO를 만듭니다.

cake acl create aco / 'ROOT'

그런 다음 이 ROOT 컨트롤러 아래의 모든 컨트롤러에 대한 ACO를 생성합니다.

cake acl create aco 'ROOT' 'MyController' ... etc ...

지금까지는 평범했습니다.aros_acos 테이블에 다음 필드를 추가합니다. _editown ACL 구성 요소의 actionMap에서 추가 작업으로 사용할 수 있습니다.

CREATE TABLE IF NOT EXISTS `aros_acos` (
`id` int(11) NOT NULL auto_increment,
`aro_id` int(11) default NULL,
`aco_id` int(11) default NULL,
`_create` int(11) NOT NULL default '0',
`_read` int(11) NOT NULL default '0',
`_update` int(11) NOT NULL default '0',
`_delete` int(11) NOT NULL default '0',
`_editown` int(11) NOT NULL default '0',
PRIMARY KEY  (`id`),
KEY `acl` (`aro_id`,`aco_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

그런 다음 AclComponent::check()에 대해 요청된 컨트롤러/작업의 유효성을 검사하는 'crud' 메서드를 사용하도록 Auth 구성 요소를 설정할 수 있습니다.app_controller에는 다음과 같은 내용이 있습니다.

private function setupAuth() {
    if(isset($this->Auth)) {
        ....
        $this->Auth->authorize = 'crud';
        $this->Auth->actionMap = array( 'index'     => 'read',
                        'add'       => 'create',
                        'edit'      => 'update'
                        'editMine'  => 'editown',
                        'view'      => 'read'
                        ... etc ...
                        );
        ... etc ...
    }
}

다시 말하지만, 이것은 상당히 표준적인 CakePHP 항목입니다.그런 다음 AppController에 그룹 수준 항목을 추가하여 액세스를 위해 그룹 ARO 또는 사용자 ARO를 확인할지 여부를 확인하는 checkAccess 메소드가 있습니다.

private function checkAccess() {
    if(!$user = $this->Auth->user()) {
        $role_alias = 'Role-1';
        $user_alias = null;
    } else {
        $role_alias = 'Role-' . $user['User']['role_id'];
        $user_alias = 'User-' . $user['User']['id'];
    }

    // do we have an aro for this user?
    if($user_alias && ($user_aro = $this->User->Aro->findByAlias($user_alias))) {
        $aro_alias = $user_alias;
    } else {
        $aro_alias = $role_alias;
    }

    if ('editown' == $this->Auth->actionMap[$this->action]) {
        if($this->Acl->check($aro_alias, $this->name, 'editown') and $this->isMine()) {
            $this->Auth->allow();
        } else {
            $this->Auth->authorize = 'controller';
            $this->Auth->deny('*');
        }
    } else {
        // check this user-level aro for access
        if($this->Acl->check($aro_alias, $this->name, $this->Auth->actionMap[$this->action])) {
            $this->Auth->allow();
        } else {
            $this->Auth->authorize = 'controller';
            $this->Auth->deny('*');
        }
    }
}

그만큼 setupAuth() 그리고 checkAccess() 메소드는 AppController'에스 beforeFilter() 콜백.거기에 isMine 요청된 항목의 user_id가 현재 인증된 사용자와 동일한지 확인하는 AppControler의 메서드(아래 참조)도 마찬가지입니다.명확성을 위해 이것을 생략했습니다.

그게 전부입니다.그런 다음 특정 acos에 대한 특정 그룹의 액세스를 허용/거부할 수 있습니다.

cake acl grant 'Role-2' 'MyController' 'read'

cake acl grant 'Role-2' 'MyController' 'editown'

cake acl deny 'Role-2' 'MyController' 'update'

cake acl deny 'Role-2' 'MyController' 'delete'

나는 당신이 그림을 얻을 것이라고 확신합니다.

어쨌든, 이 답변은 제가 의도한 것보다 훨씬 길고 말이 안 될 수도 있지만, 여러분에게 도움이 되기를 바랍니다.

-- 편집하다 --

요청에 따라 여기에 편집된 내용이 있습니다(순전히 명확성을 위해 - 상용구 코드에는 여기서는 의미 없는 내용이 많이 있습니다). isMine() AppController에 있는 메서드입니다.오류 검사 항목도 많이 제거했지만 이것이 핵심입니다.

function isMine($model=null, $id=null, $usermodel='User', $foreignkey='user_id') {
    if(empty($model)) {
        // default model is first item in $this->uses array
        $model = $this->uses[0];
    }

    if(empty($id)) {
        if(!empty($this->passedArgs['id'])) {
        $id = $this->passedArgs['id'];
        } elseif(!empty($this->passedArgs[0])) {
            $id = $this->passedArgs[0];
        }
    }

    if(is_array($id)) {
        foreach($id as $i) {
            if(!$this->_isMine($model, $i, $usermodel, $foreignkey)) {
                return false;
            }
        }

        return true;
    }

    return $this->_isMine($model, $id, $usermodel, $foreignkey);
}


function _isMine($model, $id, $usermodel='User', $foreignkey='user_id') {
    $user = Configure::read('curr.loggedinuser'); // this is set in the UsersController on successful login

    if(isset($this->$model)) {
        $model = $this->$model;
    } else {
        $model = ClassRegistry::init($model);
    }

    //read model
    if(!($record = $model->read(null, $id))) {
        return false;
    }

    //get foreign key
    if($usermodel == $model->alias) {
        if($record[$model->alias][$model->primaryKey] == $user['User']['id']) {
            return true;
        }
    } elseif($record[$model->alias][$foreignkey] == $user['User']['id']) {
        return true;
    }

    return false;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top