如何使用SLIM处理多租户?

时间:2019-07-07 19:17:00

标签: php database api slim multi-tenant

我正在使用SLIM编写一个API,该API的目标是创建一个多租户结构。到目前为止,我所做的是:

首先,我创建了一个 master 数据库,其中包含我的所有客户(购买了我的软件),对于每个客户,我都有一个名为CUSTOMER_TOKEN的字段,该字段代表凭据来访问API。

基本上,我在这里有两个软件:

  • API:从租户数据库中读取数据。
  • 主要应用程序:使用API​​。

事实上,每个租户都有一个不同的数据库,我发现这种方式对我来说是最佳选择。

主应用程序获得JWT令牌,方法是使用APICUSTOMER_TOKEN发送请求,例如:

http://xxx.xxx.xxx.xxx/v1/auth/login

上述路线将在 master 数据库中检查客户的存在(如果存在),然后将返回临时访问令牌以使用API(JWT)。

到目前为止一切都很好。主要问题来了。实际上,如果用户拥有JWT并且CUSTOMER_TOKEN有效,则API应该创建与tenant数据库的连接,而不是 master < / strong>数据库。

此刻,为了处理主连接,我特别使用了SLIM容器:

<?php
   use Slim\Container;

   $container = $app->getContainer();

   $container['pdo'] = function (Container $c) {
       $db = $c['settings']['db'];
        $pdo = new PDO(
            "mysql:host=" . $db['host'] . ";dbname=" . $db['dbname'],
            $db['user'],
            $db['pass']
        );
        return $pdo;
    };

如何从此处创建与租户数据库的不同连接?我应该使用middleware吗?我应该检查请求的路由器以了解是否需要主数据库或租户数据库吗?

请注意,对于每个租户,我使用一个名称约定结构,例如:

app_name-tenant-tenant_name

因此,我的前缀为app_name-tenant,然后是tenant_name。因此,我只需要从 master 数据库获取customer的名称即可组装连接。

您将如何处理这种情况?谢谢。

1 个答案:

答案 0 :(得分:1)

出于安全和实际原因,我建议使用两个不同的PDO连接(实例)。第一个连接用于API(JWT)Auth,第二个数据库连接用于客户(租户)。您不需要中间件,因为基础结构配置中的数据库连接部分位于中间件下方。

您有多个选项可以与容器结合使用来管理数据库连接。

  1. 只需为容器条目添加第二个别名即可,例如pdo2db2或对您有意义的类似物。
// API
$container['pdo'] = function (Container $container) {
// Customer database
$container['pdo2'] = function (Container $container) {
  1. 我希望您使用constructor dependency injection。如果是,则最好使用类或接口名称定义容器条目。

示例:

class ApiDatabase extends PDO {}

$container[ApiDatabase::class] = function (Container $container) {
class CustomerDatabase extends PDO {}

$container[CustomerDatabase::class] = function (Container $container) {
  

名称约定

现在,您已经为客户建立了第二个数据库连接,不再需要表前缀,因为在技术上客户之间已经有了更好的分隔。为什么?数据库事务也完全分开,这对其他客户数据(和表)没有影响。数据库迁移将更加容易,因为您不必担心前缀。现在,您可以为每个客户部署新版本,而不会影响其他客户的数据库。