4

使用 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- 我的不同索引操作(每个索引,每个相关控制器),我使用分页条件检查 client_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);
4

3 回答 3

1

您还可以通过在模型的 beforeFind 函数中放置一些东西来将 client_id 条件应用于模型的所有查找。

例如,在您的 User 模型中,您可以执行以下操作:

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 在新记录中自动为您设置该 client_id。

于 2012-11-07T21:07:58.230 回答
1

这个概念很好——它不是“肮脏的”,它与我处理此类情况的方式几乎完全相同。

你刚刚得到了几行冗余代码。第一的:

$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')

尽管您似乎不需要它。

于 2012-11-06T22:36:28.693 回答
0

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

在公共模式(公共数据库)中,我存储需要在所有客户端(在您的情况下没有 client_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 在任何查询中的任何参与,因为只有公司相关数据存储在该模式(数据库)中。这也增加了扩展项目的能力。

这种方法的缺点是在结构更改时同步所有数据库结构会很麻烦,但可以通过导出数据、删除所有数据库、使用新布局重新创建它们并再次导入数据来完成。只需要确保导出带有完整插入的数据,包括列名。

于 2012-11-07T23:01:12.100 回答