简体   繁体   中英

How to handle multi tenancy with SLIM?

I'm writing an API using SLIM , the goal of that API is create a multi tenant structure. What I did so far is the following:

First of all, I have created a master database which contains all my customers (who bought my software), for each customer I have a field called CUSTOMER_TOKEN , which represents the credentials to access to the API.

Basically, I have two software here:

  • API: read the data from the tenant database.
  • Main application: use the API.

Infact, each tenant have a different database, I find this way the best choice for me.

Main application get a JWT token sending a request to the API by using the CUSTOMER_TOKEN , eg:

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

the route above will check the customer existence on the master database, if exists, then will return a temporary access token to use the API (JWT).

So far all good. The main problem come's here. Infact, if the user has got the JWT and the CUSTOMER_TOKEN is valid, then the API should create a connection to the tenant database rather than the master database.

At the moment, for handle the main connection, I use the SLIM container, in particular:

<?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;
    };

how can I create a different connection to the tenant database from here? Should I use a middleware ? Should I check the requested router to understand if I need the master db or tenant db?

Take as note that for each tenant I use a name convention structure such as:

app_name-tenant-tenant_name

So I have the prefix as app_name-tenant and then the tenant_name . So I only need to get the name of the customer from the master db to assemble the connection.

How would you manage this situation? thank you.

For security and practical reasons I would recommend using two different PDO connections (instances). The first connection is for the API (JWT) Auth and the second database connection is for the customer (tenant). You don't need a middleware, because the database connection part of the infrastructure configuration and below the middleware.

You have multiple options to manage the database connections in combination with a container.

  1. Just add a second alias name for the container entry like pdo2 or db2 or someting similar that makes sense for you.
// API
$container['pdo'] = function (Container $container) {
// Customer database
$container['pdo2'] = function (Container $container) {
  1. I hope you use constructor dependency injection . If yes, better define the container entries with a class or the interface name.

Example:

class ApiDatabase extends PDO {}

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

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

name convention

Now you have a second database connection for the customer, a table prefix is no longer necessary because you already have a technically better separation between the customers. Why? Database transactions are also completely separated, which has no effect on other customer data (and tables). Database migrations will be easier because you don't have to worry about prefixes. Now you can deploy new versions per customer without affecting other customers' database.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM