首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CakePHP ACL数据库设置: ARO / ACO结构?

CakePHP ACL数据库设置: ARO / ACO结构?
EN

Stack Overflow用户
提问于 2008-09-10 14:39:38
回答 1查看 27K关注 0票数 21

我正在努力在CakePHP中实现ACL。在阅读了cake manual中的文档以及其他几个教程、博客文章等之后,我发现Aran Johnson的优秀教程帮助填补了许多空白。他的例子似乎与我在一些地方看到的其他例子相冲突-特别是在他使用的ARO树结构中。

在他的examples中,他的用户组被设置为级联树,最常见的用户类型位于树的顶部,其子级分支用于每个更受限制的访问类型。在其他地方,我通常会看到每个用户类型都是同一通用用户类型的子类。

如何在CakePHP中设置ARO和ACO?任何和所有的技巧都很感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2008-09-11 13:36:18

CakePHP的内置ACL系统非常强大,但在实际实现细节方面的文档很少。我们在许多基于CakePHP的项目中成功使用的系统如下所示。

它是对一些组级访问系统的修改,这些系统一直是documented elsewhere。我们的系统的目标是拥有一个简单的系统,其中用户在组级别上被授权,但他们可以对他们创建的项目拥有特定的额外权限,或者基于每个用户。我们希望避免在aros_acos表中为每个用户(或者更具体地说,为每个ARO)创建一个特定的条目。

我们有一个用户表和一个角色表。

用户

user_id, user_name, role_id

角色

id, role_name

为每个角色创建ARO树(我们通常有4个角色-未授权访客(id 1)、授权用户(id 2)、站点版主(id 3)和管理员(id 4)):

cake acl create aro / Role.1

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

在此之后,您必须使用SQL或phpMyAdmin或类似的工具为所有这些添加别名,因为蛋糕命令行工具不能做到这一点。我们所有的代码都使用'Role-{id}‘和'User-{id}’。

然后我们创建一个根ACO -

cake acl create aco / 'ROOT'

然后为这个根目录下的所有控制器创建ACOs:

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

到目前为止一切正常。我们在aros_acos表中添加了一个名为_editown的附加字段,我们可以将其用作ACL组件的actionMap中的附加操作。

代码语言:javascript
复制
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;

然后,我们可以将Auth组件设置为使用“crud”方法,该方法根据AclComponent::check()验证所请求的控制器/操作。在app_controller中,我们有一些类似的东西:

代码语言:javascript
复制
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中有一个checkAccess方法,它添加了组级别的内容,以检查是否检查组ARO或用户ARO以进行访问:

代码语言:javascript
复制
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()方法是在AppControllerbeforeFilter(回调中调用的。AppControler中也有一个isMine方法(如下所示),它只是检查请求项的user_id是否与当前已验证的用户相同。为了清楚起见,我省略了这一点。

这真的是所有的事情了。然后,您可以允许/拒绝特定组访问特定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'

我相信你已经明白了。

无论如何,这个答案比我预期的要长得多,而且它可能几乎没有任何意义,但我希望它能对你有所帮助……

-编辑--

按照要求,这里有一个经过编辑的AppController中的isMine()方法(纯粹为了清晰起见,我们的样板代码中有很多东西在这里是没有意义的)。我也删除了很多错误检查的东西,但这是它的本质:

代码语言:javascript
复制
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;
}
票数 51
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54230

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档