Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/233.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
CakePHP:基于belongsTo关系授权操作_Php_Cakephp_Authorization_Cakephp 2.0 - Fatal编程技术网

CakePHP:基于belongsTo关系授权操作

CakePHP:基于belongsTo关系授权操作,php,cakephp,authorization,cakephp-2.0,Php,Cakephp,Authorization,Cakephp 2.0,让我们保持简单 一个项目只有两个模型: 用户(有许多项目) 项目(属于用户) 用户只允许对他们所拥有的项目执行操作。没有别人的 我知道如何手动检查登录用户是谁,以及他/她是否拥有特定的项目,但是否有更好、更全面的方法来做到这一点?我正在寻找一种更为D.R.Y.的方法,它不需要在多个操作中重复相同的验证。例如,是否有一个配置设置,例如 Configure::write('Enforce\u-belishing\u-to',true) …或者可能是Auth组件上的设置/选项 也许这太疯狂了,但我想我

让我们保持简单

一个项目只有两个模型:

  • 用户(有许多项目)
  • 项目(属于用户)
  • 用户只允许对他们所拥有的项目执行操作。没有别人的

    我知道如何手动检查登录用户是谁,以及他/她是否拥有特定的项目,但是否有更好、更全面的方法来做到这一点?我正在寻找一种更为D.R.Y.的方法,它不需要在多个操作中重复相同的验证。例如,是否有一个配置设置,例如

    Configure::write('Enforce\u-belishing\u-to',true)

    …或者可能是Auth组件上的设置/选项


    也许这太疯狂了,但我想我会问的。

    我不确定我的回答是否是最好的、最干燥的、几乎是脱水的方法,但这是我能想到的最简单的方法

    在项目模型中,创建一个函数,该函数返回与用户关联的项目ID数组

    class Project extends AppModel {
        public function getByUserId($userId) {
            $projectsArray = array();
    
            if ($userId != "valid")
               //do all the checks, if it's not null, numeric, if the id exists, etc
    
            $projects = $this->Project->find('all', array('conditions'=>
                            array('user_id'=>$userId)));
            if (!empty($projects)) {
                foreach($projects as $i => $project)
                    $projectsArray[] = $project['Project']['id'];
            }
            return $projectsArray;
        }
    }
    
    您在评论中提到了一个
    find('first')
    ,但我假设您希望所有与用户相关的项目,而不仅仅是第一个项目。如果不是,它只是对该函数的简单修改。另外,我只是在获取id,但您可能需要一个
    $id=>$name\u项目
    数组,由您决定

    现在,我不知道你所说的“只允许执行操作”是什么意思,只是编辑受到限制吗?或者,如果项目不是用户的,列表或视图应该受到限制,甚至不向用户显示

    对于第一种情况,限制编辑,在保存之前修改

    public function beforeSave($options = array()) {
        if(!$this->id && !isset($this->data[$this->alias][$this->primaryKey])) {
            //INSERT
            //not doing anything
        } else {
            //UPDATE
            //check if project inside allowed projects array
            $allowed = $this->getByUserId(CakeSession::read("Auth.User.id"));
            if (!in_array($this->id, $allowed))
               return false; //or throw error and catch it in the controller
        }
         return true;
    }
    
    代码未经测试,但一般来说,您会阻止在更新记录之前编辑非“用户”的项目。我假设插入新项目对每个人都是免费的。根据,除了
    saveAll
    之外的所有保存功能都会首先通过此过滤器,因此您需要覆盖
    saveAll
    功能,并添加一个类似于
    保存前的验证(如回答中所述)

    对于第二部分,过滤结果以便用户甚至不知道还有其他项目而不是他/她的项目,请在查找之前更改
    。讨论根据用户角色限制结果,所以我想我们的思路是正确的

    public function beforeFind($queryData) {
        //force the condition
        $allowed = $this->getByUserId(CakeSession::read("Auth.User.id"));
        $queryData['conditions'][$this->alias.'.user_id'] = $allowed;
    
        return $queryData;
    }
    
    由于
    $allowed
    数组只有id值,因此它的工作方式类似于
    子句中的
    ,但是如果更改该数组结构,请确保相应地修改这些函数

    就这样。我在考虑更基本的案例,编辑,查看,删除。。。Ups,删除。。。同时更改
    beforeDelete
    功能,以避免任何想要删除他人属性的恶意用户。逻辑保持不变(检查项目id是否在允许的数组中,如果不在,则返回false或throw error),因此我不会在这里添加该函数的示例。但这是最基本的东西。如果出于某种原因希望在控制器中拥有允许的项目,请调用
    beforeFilter
    中的
    getByUserId
    函数,并在那里处理该ID数组。您甚至可以将其存储在会话中,但在添加或删除项目时必须记住维护该会话

    如果希望超级管理员可以查看和编辑所有内容,只需在
    getByUserId
    中添加一个检查用户角色的条件,如果是管理员,则返回所有项目

    另外,请记住:也许这个项目有很多。。。子项目(没有太多的想象力),因此,与项目相关的用户可以添加子项目,但与之前相同的邪恶用户修改子项目的隐藏项目id并对其进行编辑。在这种情况下,我建议您也在子项目中添加验证,以避免在与项目相关的模型上执行非his的操作。如果您已经准备好了安全组件,并且编辑和删除操作只能由表单完成,这是一件小事,因为安全组件的良好使用避免了表单篡改。但请考虑一下,您是否也需要验证“子项目”实例

    如前所述,您可以将所有这些用作行为。我个人没有这样做,但它会遇到,这里修改的所有回调都是您在行为中修改的。您必须封装逻辑、列名(必须是变量,而不是硬编码设置,如
    user\u id
    )等,但它可以在您拥有的任何其他cake项目中重用。类似于
    StrongBelongBehavior
    MoreDRYBehavior
    。如果您这样做了,请与他人分享:)

    我不确定Auth组件是否有某种方法可以实现您想要的功能,但我想这是最好的选择。除非有人告诉我(我没有对这个问题做过太多的调查),否则这就是我会使用的解决方案。

    除了我的答案之外,下面是关于行为的一般概念。然后可以将其附着到适用的模型

        class StrongBelongBehavior extends ModelBehavior
        {
           public function beforeFind(  Model $Model, $query = array() ) { 
             $query['conditions'] = array_merge( (array)$query['conditions'], array( $Model->alias.'.user_id' => CakeSession::read("Auth.User.id" ) );
             return $query;
           }
    
           public function beforeSave( Model $Model ) {
            $projectId = Hash::get( $Model->data, 'Poject.id' );
            if( $projectId ) {
               $Model->loadModel('UserProject'); // UserProject is a custom model
               $canEdit =  $Model->UserProject->projectIDExists( $projectId ); // returns true if projectId belongs to the current user
               if ( ! $canEdit  ) {
                 return false;
               }
            }
           return true;
           }
         }
    

    你现在是如何执行验证的?你想过使用行为吗?@Nunser。我将项目ID传递给
    $this->project->find('first')
    ,并添加
    project.User.ID=###
    ,其中###是Auth组件返回的当前用户。所以,如果是别人的项目,就不会有项目被退回。@AyoAkinyemi不确定你的建议是什么。有兴趣听到更多。