Créer une application multi-tenant présente des défis uniques, en particulier lorsqu'il s'agit de gérer l'authentification et l'autorisation des utilisateurs sur plusieurs locataires. Dans cet article, je vais vous expliquer comment implémenter ASP.NET Identity dans un environnement multi-tenant tout en suivant les meilleures pratiques pour garantir l'évolutivité, la sécurité et la maintenabilité.
Une application multi-tenant permet à plusieurs organisations (tenants) d’utiliser la même instance d’une application, les données de chaque locataire étant isolées des autres. Cette architecture est efficace pour la mise à l'échelle et le partage des coûts, mais nécessite une attention particulière lors de la gestion de l'authentification et de l'autorisation des utilisateurs.
ASP.NET Identity est un cadre flexible pour gérer l'authentification et la gestion des utilisateurs. Pour l'adapter à une configuration multi-tenant, vous devez :
Dans une application multi-tenant, chaque utilisateur doit être associé à un locataire spécifique. Vous pouvez modifier le modèle ASP.NET Identity User en ajoutant une propriété TenantId pour suivre le locataire auquel appartient un utilisateur.
public class ApplicationUser : IdentityUser { public string TenantId { get; set; } }
Ensuite, étendez IdentityDbContext pour prendre en charge les données spécifiques au locataire en vous assurant que les requêtes sont filtrées en fonction du TenantId.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // Add a global query filter to isolate data by tenant builder.Entity<ApplicationUser>().HasQueryFilter(u => u.TenantId == GetCurrentTenantId()); } private string GetCurrentTenantId() { // Implement logic to retrieve the current tenant's ID, e.g., from the request or context return TenantResolver.ResolveTenantId(); } }
Pour garantir que chaque utilisateur est associé au bon locataire, vous aurez besoin d'un résolveur de locataire pour déterminer à quel locataire la demande actuelle est liée. Cela peut être basé sur le sous-domaine, un segment d'URL ou un en-tête personnalisé.
public static class TenantResolver { public static string ResolveTenantId() { // Example: Resolve tenant from subdomain or URL segment var host = HttpContext.Current.Request.Host.Value; return host.Split('.')[0]; // Assuming subdomain is used for tenant identification } }
Dans une application multi-tenant, il est essentiel de s'assurer que les utilisateurs ne peuvent s'authentifier qu'avec leurs informations d'identification spécifiques au locataire. Personnalisez la logique de connexion pour vérifier le TenantId lors de l'authentification.
public class CustomSignInManager : SignInManager<ApplicationUser> { public CustomSignInManager(UserManager<ApplicationUser> userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor, ILogger<SignInManager<ApplicationUser>> logger, IAuthenticationSchemeProvider schemes, IUserConfirmation<ApplicationUser> confirmation) : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation) { } public override async Task<SignInResult> PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure) { // Resolve tenant before signing in var tenantId = TenantResolver.ResolveTenantId(); var user = await UserManager.FindByNameAsync(userName); if (user == null || user.TenantId != tenantId) { return SignInResult.Failed; } return await base.PasswordSignInAsync(userName, password, isPersistent, lockoutOnFailure); } }
Chaque locataire peut avoir son propre ensemble de rôles et d'autorisations. Modifiez votre modèle de rôle pour inclure un TenantId et ajustez les vérifications de rôle pour tenir compte du locataire actuel.
public class ApplicationRole : IdentityRole { public string TenantId { get; set; } }
Avec les applications multi-tenant, l'isolation des données est cruciale. En plus de sécuriser l’authentification et l’autorisation, assurez-vous que les utilisateurs ne peuvent accéder qu’aux données spécifiques au locataire. Appliquez des filtres de requête globaux dans votre DbContext ou utilisez des modèles de référentiel pour filtrer les données en fonction du TenantId actuel.
public class UserRepository : IUserRepository { private readonly ApplicationDbContext _context; public UserRepository(ApplicationDbContext context) { _context = context; } public IQueryable<User> GetUsers() { var tenantId = TenantResolver.ResolveTenantId(); return _context.Users.Where(u => u.TenantId == tenantId); } }
Lorsque vous testez une application multi-tenant, assurez-vous :
À l'aide de tests unitaires et de tests d'intégration, simulez la résolution des locataires et assurez-vous que la logique spécifique au locataire est appliquée.
[TestMethod] public async Task User_Should_Only_See_Tenant_Data() { // Arrange var tenantId = "tenant_1"; var tenantUser = new ApplicationUser { UserName = "user1", TenantId = tenantId }; // Act var result = await _signInManager.PasswordSignInAsync(tenantUser.UserName, "password", false, false); // Assert Assert.AreEqual(SignInResult.Success, result); }
La mise en œuvre de l'identité ASP.NET dans un environnement multi-tenant peut s'avérer difficile, mais avec les bonnes pratiques, vous pouvez garantir l'évolutivité, la sécurité et l'isolation des données. En suivant les étapes décrites dans ce guide, vous serez en mesure de créer un système de gestion des identités multi-locataires robuste et adapté aux besoins de chaque locataire.
Faites-moi savoir si vous avez rencontré des défis similaires ou si vous avez d'autres bonnes pratiques pour les applications multi-locataires. J'aimerais entendre vos réflexions dans les commentaires !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!