(Or ASP.NET Core Multi-Tenant Identity)
Long name for a simple purpose: add multi-tenant support to ASP.NET Core Identity.
This project is built on .NET Standard 2.0. It currently works with ASP.NET Core Identity version 2.1.
To get the basics, install the core package from NuGet:
Install-Package Eleven41.AspNetCore.MultiTenantIdentity
- Add
usingdirectives where required:
using Eleven41.AspNetCore.MultiTenantIdentity;- Derive your user class from
MultiTenantUserrather thanIdentityUser:
class ApplicationUser : MultiTenantUser
{
}You can also derive from MultiTenantUser<> to indicate the key type.
The MultiTenantUser class adds a TenantId member to your users to indicate the tenant they are a member of. This new property is required. So it must be set on your user before the user is added to your store.
Please see the samples for a registration example.
- If you are also using roles, derive your role class from
MultiTenantRolerather thanIdentityRole:
class ApplicationRole : MultiTenantRole
{
}Similarly, you can template the MultiTenantRole<> with the key type.
- This package introduces a new class called
IdentityTenantthat represents the tenants (groups, organizations, companies) that your users are contained within. This class can be templated usingIdentityTenant<>to indicate the key type.
Note: Key types should be the same between users, roles, and tenants.
- In
Startup.cs, install the core services after your
services.AddDefaultIdentity<ApplicationUser>()
.AddMultiTenantIdentity<ApplicationTenant>()
;This will add TenantManager<ApplicationUser, ApplicationTenant> into the dependency injection services.
In your controllers, access the tenant manager as follows:
class HomeController
{
TenantManager<ApplicationUser, ApplicationTenant> _tenantManager;
public HomeController(TenantManager<ApplicationUser, ApplicationTenant> tenantManager)
{
_tenantManager = tenantManager ?? throw new ArgumentNullException(nameof(tenantManager));
}
public async Task<IActionResult> Index()
{
if (this.User.Identity.IsAuthenticated)
{
var user = await _userManager.GetUserAsync(this.User);
var tenant = await _tenantManager.FindByIdAsync(user.TenantId.ToString());
ViewData["TenantName"] = await _tenantManager.GetNameAsync(tenant);
}
return View();
}
}If you are using Entity Framework Core for your identity storage, you should also install the Entity Framework middleware:
Install-Package Eleven41.AspNetCore.MultiTenantIdentity.EntityFrameworkCore
- Add
usingdirectives where required:
using Eleven41.AspNetCore.MultiTenantIdentity.EntityFrameworkCore;- Derive your Identity context from
MultiTenantIdentityDbContext(if you are using roles) orMultiTenantIdentityUserContextif you are not using roles. Basically, just putMultiTenantat the start of the base class you're using.
public class ApplicationIdentityContext : MultiTenantIdentityUserContext<ApplicationUser, ApplicationTenant>
{
public ApplicationIdentityContext(DbContextOptions<ApplicationIdentityContext> options)
: base(options)
{
}
}- In
Startup.cs, callAddMultiTenantEntityFrameworkStoreswith your identity context class.
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<IdentityContext>()
.AddMultiTenantIdentity<ApplicationTenant>()
.AddMultiTenantEntityFrameworkStores<ApplicationIdentityContext>()
;-
Add a database migration.
dotnet ef migrations add AddMultiTenancy
-
Update your database.
dotnet ef database update
At this point, you should see 2 things in your database:
- A new table was added called
AspNetTenants. - The
AspNetUserstable should have a new column calledTenantIdwith a foreign key pointing toAspNetTenants.
- User names and emails must still follow the normal Identity uniqueness requirements. Users are not isolated within tenants.
- Adding multi-tenancy to an existing database is currently problematic since the
TenantIdadded to users is non-null and required.
- Add user management pages to add to your MVC applications to add/remove users within a tenant.
- Add optional user isolation to allow the same username and email in multiple tenants.