Image de couverture : Multi-Tenancy dans un SaaS : protégez vos données et vos clients dès la conception
tech

Multi-Tenancy dans un SaaS : protégez vos données et vos clients dès la conception

16 March 2026
7 min de lecture
27 vues
Sébastien Muler

Multi-Tenancy dans un SaaS : protégez vos données et vos clients dès la conception

Chaque application SaaS doit répondre à une question fondamentale à chaque requête : qui peut faire quoi, et dans quelle entreprise ? En apparence simple, cette problématique cache une complexité architecturale que beaucoup de développeurs sous-estiment au démarrage d'un projet.

Dmitry Isaenko, développeur de la solution SaaS Kohana.io (un CRM/ERP pour PME), a partagé sur dev.to le retour d'expérience de la construction complète d'un système multi-tenancy sous Laravel, sans recourir au package Spatie. Cet article s'inspire de son travail pour vous présenter les enjeux clés d'une telle architecture et les décisions techniques qui en découlent.


Qu'est-ce que le multi-tenancy et pourquoi est-ce critique ?

Le multi-tenancy (ou multi-location) désigne la capacité d'une application à servir plusieurs clients (les "tenants") de manière isolée, au sein d'une même infrastructure. Chaque client perçoit l'application comme si elle lui était dédiée, sans jamais accéder aux données des autres.

Dans un contexte SaaS, c'est une exigence non négociable. La moindre faille peut entraîner une fuite de données entre deux organisations clientes : imaginez les commandes de l'entreprise A visibles par l'entreprise B. Ce type d'incident est catastrophique, tant sur le plan légal (RGPD) que sur celui de la confiance client.

Les décisions architecturales à prendre sont nombreuses :

  • Base de données unique ou bases séparées par tenant ?
  • Gestion des permissions par configuration ou en base de données ?
  • Comment gérer les surcharges de permissions ?
  • Comment réagir proprement à une erreur 403 ?

Ces choix ont des impacts durables sur la maintenabilité, la performance et la sécurité du système.


L'isolation des données : le principe du moindre accès

La pierre angulaire d'un système multi-tenancy robuste est l'isolation des données. Le bug le plus redouté est simple : un WHERE company_id = ... oublié dans une requête, et les données d'un client deviennent accessibles à un autre.

Pour éliminer ce risque structurellement, l'approche recommandée consiste à centraliser ce filtrage via un trait Eloquent. Dans l'architecture décrite par Isaenko pour Laravel, le trait BelongsToCompany applique automatiquement un scope global sur chaque modèle concerné, garantissant que toutes les requêtes sont systématiquement filtrées par l'entreprise active du tenant courant.

// Exemple simplifié du principe en Symfony/Doctrine
// Un EventSubscriber applique automatiquement le filtre tenant
public function onPreFind(LoadClassMetadataEventArgs $args): void
{
    $filters = $this->entityManager->getFilters();
    if (!$filters->isEnabled('tenant_filter')) {
        $filters->enable('tenant_filter')->setParameter('company_id', $this->tenantContext->getCompanyId());
    }
}

L'idée est la même quelle que soit la stack : le développeur ne doit pas avoir à y penser. Le filtre s'applique de façon transparente, et une exception explicite doit exister pour les rares cas où l'on souhaite contourner ce mécanisme (scripts d'administration, jobs globaux, etc.).


Gestion des rôles et permissions : une hiérarchie claire

Une fois l'isolation des données assurée, la question des autorisations se pose. Qui peut accéder à quoi au sein d'un même tenant ?

L'architecture présentée s'appuie sur plusieurs principes solides :

1. Une source de vérité unique pour les permissions

Toutes les permissions sont définies dans un fichier de configuration centralisé (config/roles-and-permissions.php sous Laravel, ou équivalent YAML sous Symfony). Cela évite la dispersion des règles métier dans le code et facilite les audits de sécurité.

2. Une hiérarchie de permissions à plusieurs niveaux

Il ne suffit pas d'avoir "admin" ou "user". Un SaaS réaliste nécessite une hiérarchie fine. L'implémentation décrite propose cinq niveaux :

  • Permissions globales de l'application
  • Permissions par rôle
  • Permissions spécifiques à un utilisateur
  • Surcharges positives (accorder un droit supplémentaire)
  • Surcharges négatives (révoquer un droit spécifique)

Cette granularité permet de couvrir des cas métier complexes sans multiplier les rôles.

3. Des classes Gate dédiées par module

Plutôt que de concentrer toute la logique d'autorisation dans un seul fichier, l'architecture segmente les règles par domaine fonctionnel (facturation, contacts, projets, etc.). Chaque module possède sa propre classe Gate, ce qui améliore la lisibilité et la maintenabilité.


Le contexte tenant : résolution automatique et middlewares

Un système multi-tenancy efficace doit résoudre automatiquement le contexte du tenant à chaque requête, sans que le développeur ait à le gérer manuellement dans chaque contrôleur.

Deux middlewares jouent un rôle central dans cette architecture :

  • SetActiveCompanyMiddleware : résout et injecte le contexte du tenant actif (l'entreprise courante de l'utilisateur connecté) dès le début du cycle de vie de la requête.
  • CheckAccessMiddleware : vérifie les conditions d'accès transversales — compte banni, abonnement expiré, accès révoqué — et redirige proprement si nécessaire.

Ce découplage est essentiel. La résolution du tenant et la vérification des droits sont deux responsabilités distinctes, et les séparer en middlewares dédiés respecte le principe de responsabilité unique.

Sous Symfony, ce pattern se traduit naturellement par des EventListener sur le kernel ou des RequestListener qui s'exécutent avant chaque contrôleur.


Ce que cela change concrètement pour vos clients

Au-delà de l'aspect technique, un système multi-tenancy bien conçu a des conséquences directes sur la confiance et la satisfaction client :

  • 🔒 Sécurité des données : chaque client a l'assurance que ses informations sont hermétiquement isolées de celles des autres.
  • Performance maîtrisée : les requêtes sont toujours filtrées au bon niveau, sans surcharge inutile.
  • 🛠️ Maintenabilité : les règles métier centralisées et les middlewares dédiés réduisent considérablement le risque de régression lors des évolutions.
  • 📋 Conformité RGPD : l'isolation des données par tenant facilite la mise en œuvre des droits à l'effacement et à la portabilité.

Conclusion

Constructing un système multi-tenancy de qualité professionnelle demande du temps — non pas parce que le code est complexe, mais parce que les décisions d'architecture le sont. Comme le résume Isaenko, ce module a pris plus de temps que tout autre dans son SaaS, précisément parce qu'il faut anticiper les cas limites, les surcharges de permissions, les fuites de données potentielles.

Que vous travailliez avec Laravel ou Symfony, les principes restent les mêmes : isolation automatique des données via des filtres globaux, hiérarchie de permissions claire et centralisée, résolution transparente du contexte tenant, et middlewares dédiés pour les vérifications transversales.

Chez MulerTech, nous accompagnons les équipes dans la conception et l'implémentation de ce type d'architecture sur des projets Symfony. Si vous lancez un SaaS ou si vous cherchez à sécuriser une application multi-clients existante, ces fondations architecturales sont un investissement qui protège vos clients — et votre réputation.

Source originale : How I Built a Complete Multi-Tenancy System for My Laravel SaaS - Without Spatie par Dmitry Isaenko sur dev.to.

Partager cet article