根据特定的客户端ID过滤访问控制器操作的最佳方法



使用cakephp 2.2,我正在构建一个应用程序,其中每个客户都有其自己的"数据领域",而其他数据都不可见。例如,客户有他的一组用户,课程,承包商和工作。小组在客户之间共享,但他们无法在小组上执行动作。所有客户端都可以使用组来分配给用户。因此,管理员(使用ACL)只能从同一客户端ID管理数据。

我所有的对象(当然,除组除外)都有client_id键。

现在,我知道完成此操作并实际运行良好的一种方法,但是看起来有点脏,我想知道是否有更好的方法。在该项目的早期,而新手是CakePHP,我渴望正确。

这就是我现在这样做的方式:

1-用户登录。他的client_id是根据用户表中的数据写入会话的。

$user = $this->User->read(null, $this->Auth->user('id'));
$this->Session->write('User.client_id', $user['User']['client_id']);

2-在AppController中,我有一个受保护的函数,将会话ID与给定参数进行比较。

protected function clientCheck($client_id) {
    if ($this->Session->read('User.client_id') == $client_id) {
        return true;
    } else {
        $this->Session->setFlash(__('Invalid object or view.'));
        $this->redirect(array('controller' => 'user', 'action' => 'home'));
    }
}

3-我是我不同的索引操作(每个索引,每个相关控制器),我使用PAGINES条件检查客户端_ID。

public function index() {
    $this->User->recursive = 0;
    $this->paginate = array(
         'conditions' => array('User.client_id' => $this->Session->read('User.client_id'))
    );
    $this->set('users', $this->paginate());
}

4-在其他操作中,我在检查http请求之前检查client_id。

$user = $this->User->read(null, $id);
$this->clientCheck($user['User']['client_id']);
$this->set('user', $user);

这个概念很好 - 它不是'脏',它与我处理这样的情况的方式几乎完全相同。

您刚刚有几行冗余代码。第一:

$this->Auth->user('id')

该方法实际上可以获取登录用户的任何字段,因此您可以执行:

$this->Auth->user('client_id')

所以您的两行:

$user = $this->User->read(null, $this->Auth->user('id'));
$this->Session->write('User.client_id', $user['User']['client_id']);

不需要。您无需重新阅读用户或将任何内容写入会话 - 只需在需要的任何时候直接从AUTH上获取client_id。

实际上,如果您阅读http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-user,甚至可以说您可以从在控制器的上下文之外,使用静态方法:

AuthComponent::user('client_id')

尽管似乎并不需要。

您也可以通过将某些内容放置在模型中的函数中。

例如,在您的用户模型中,您可以做类似的事情:

function beforeFind( $queryData ) {
    // Automatically filter all finds by client_id of logged in user
    $queryData['conditions'][$this->alias . '.client_id'] = AuthComponent::user('client_id');
    return $queryData;
}

不确定AuthComponent :: User('client_id')是否在模型中起作用,但是您会得到这个想法。这将自动将此条件应用于模型中的每个发现。

您也可以使用模型中的beforesave在新记录中自动为您设置该客户端。

我的答案可能是特定于数据库引擎,因为我使用postgresql。在我的项目中,我用MySQL术语为每个客户端使用了不同的架构,这些模式将是每个客户端的单独数据库。

在公共架构(通用数据库)中,我存储所有需要在所有客户端之间共享的数据(例如,在您的情况下没有客户端_id的对象),例如可变常数,配置文件设置等。

在公司特定型号中,我定义

public $useDbConfig = 'company_data';

Controller/AppController.php beforeFilter()方法中,我有此代码可以根据登录的用户设置架构。

if ($this->Session->check('User.Company.id')) {
    App::uses('ConnectionManager', 'Model'); 
    $dataSource = ConnectionManager::getDataSource('company_data');
    $dataSource->config['schema'] = 
        'company_'.$this->Session->read('User.Company.id');
}

如您所见,我可以随时更新数据源。这确实将Company_ID参与到任何查询中的任何参与,因为仅将相关数据存储在该模式中(数据库)。这也增加了扩展项目的能力。

这种方法的缺点是,它会在屁股上产生痛苦,以使所有数据库结构在结构变化上同步,但是可以使用导出数据,删除所有数据库,用新的布局重新创建新布局并再次导入数据。只需要确保将数据带有完整插件,包括列名。

最新更新