(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
using
directives where required:
using Eleven41.AspNetCore.MultiTenantIdentity;
- Derive your user class from
MultiTenantUser
rather 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
MultiTenantRole
rather thanIdentityRole
:
class ApplicationRole : MultiTenantRole
{
}
Similarly, you can template the MultiTenantRole<>
with the key type.
- This package introduces a new class called
IdentityTenant
that 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
using
directives where required:
using Eleven41.AspNetCore.MultiTenantIdentity.EntityFrameworkCore;
- Derive your Identity context from
MultiTenantIdentityDbContext
(if you are using roles) orMultiTenantIdentityUserContext
if you are not using roles. Basically, just putMultiTenant
at 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
, callAddMultiTenantEntityFrameworkStores
with 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
AspNetUsers
table should have a new column calledTenantId
with 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
TenantId
added 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.