-
Notifications
You must be signed in to change notification settings - Fork 159
Hierarchical Multi Tenant
The AuthP library contains a IAuthTenantAdminService
service that contains various admin features for managing multi-tenant systems. This document describes the hierarchical multi-tenant admin services and give you some examples of how they might be used in an application.
The Example4 application provides an example hierarchical multi-tenant application containing code to manage shops, with hierarchical above the shops which allow managers to see data for groups of shops. The diagram below gives you a look at part of the data shown in Example4' application.
You can clone the https://github.com/JonPSmith/AuthPermissions.AspNetCore/ and run this application to see how it works. NOTE: You must log in as 'AppAdmin@g1.com' or 'Super@g1.com' to access all the admin features, or the shop users (e.g. Tie4UManager@4uInc.com) to access the stock / sales data for that shop.
Here is a list of the various methods used to, with examples from Example4 application in the repo. These use methods in the IAuthTenantAdminService
service. NOTE: The IAuthTenantAdminService contains comments on each method.
Say a new company wants to use your application, then you would create a new Tenant
, which would provide a DataKey
for filtering your application's data. To create a hierarchical tenant you use the tenant admin AddHierarchicalTenantAsync
method (see code below). The tenant name provided with be prefixed by the parent's name, for instance adding a tenant named "Tie4U" to the parent with the full name of "4U Inc. | West Coast | LA" would mean the full name of the created tenant would be "4U Inc. | West Coast | LA | Tie4U", and must be unique, or an error will be returned.
You have to provide the TenantId
of the parent Tenant, or zero if the new Tenant should be at the top level.
var status = await _authTenantAdmin
.AddHierarchicalTenantAsync(input.TenantName, input.ParentId);
A successful call to the AddSingleTenantAsync
method will also call the CreateNewTenantAsync
method in the your implementation of the ITenantChangeService
interface (see Example4' ITenantChangeService
implementation). This allows your own application data to create a local tenant entity with the tenant name, which can be useful if you want to show the tenant name in your app.
AuthP' IAuthUsersAdminService
contains code to edit an AuthP user, which includes adding / changing / removing a tenant to a user. The screenshot below come from Example4' AuthUsersController
and shows a dropdown box for selecting the AuthP tenant for a user.
NOTE: If AuthP user hasn't got a Tenant class linked to it, then that user can't access any of the multi-tenant data.
There are five method for obtaining AuthP Tenants data:
-
QueryTenants()
, which returns aIQueryable<Tenant>
result. This allows you to list all the possible tenants. -
QueryEndLeafTenants()
, which returns aIQueryable<Tenant>
result which contains only tenants that have no children. This is useful as in some hierarchical multi-tenant systems the data is only found at the end of links. -
GetTenantViaIdAsync(int tenantId)
, which returns anIStatusGeneric<Tenant>
result. If the status is valid, then it returns theTenant
with the giventenantId
plus its Parent tenant. This is useful for getting information to show prior to an update or delete. -
GetHierarchicalTenantChildrenViaIdAsync(int tenantId)
, which returns aList<Tenant>
result, which holds all the tenants linked to the tenant with the giventenantId
. This is useful to display what other tenants will be deleted if the tenant withtenantId
is deleted. - The
IAuthUsersAdminService
service has aGetAllTenantNamesAsync()
method which returns aList<string>
result. This is useful for create dropdown lists as shown in the screenshot above.
If you need to change the name of the tenant, then you can use the tenant admin UpdateTenantNameAsync(int tenantId, string newTenantName)
method, where the newTenantName
is the name placed after the parent FullName. For instance if a tenant has a FullName of "4U Inc. | West Coast" and the newTenantName
was set the "West Area", the new FullName of the tenant would be "4U Inc. | West Area"
In addition, if the tenant has children, then their FullName is also updated, for instance the table below shows you want would happen if the tenant with the name "4U Inc. | West Coast" was changed to "4U Inc. | West Area", which has children
Before "West Coast" | After "West Area" |
---|---|
"4U Inc. | West Coast" | "4U Inc. | West Area" |
"4U Inc. | West Coast | LA" | "4U Inc. | West Area | LA" |
"4U Inc. | West Coast | LA | Shirt4U" | "4U Inc. | West Area | LA | Shirt4U" |
... and so on | ... and so on |
A successful call to the UpdateTenantNameAsync
method will also call the HandleUpdateNameAsync
method in the your implementation of the ITenantChangeService
interface (see Example4' ITenantChangeService
implementation) for each tenant that is changed. This allows your own application data to update any a local tenant entity with the tenant name change.
You can change the relationships between hierarchical tenants, which will also change the DataKey of each moved tenant, and the DataKey of the linked application data. And if the moved hierarchical tenant has children, then each child tenant has their DataKey and FullName changed. The diagram below shows how the DataKeys would be updated if a new hierarchical tenant called "California" was added and the "LA" and "SanFran" tenants are moved to this new tenant:
The AuthP tenant admin method is MoveHierarchicalTenantToAnotherParentAsync(int tenantToMoveId, int newParentTenantId)
and returns a status. The status will return errors if the move isn't valid, such trying to link the "tenantToMove" to a parent that is a child of the "tenantToMove".
This method will call the MoveHierarchicalTenantDataAsync
method in the your implementation of the ITenantChangeService
interface (see Example4' ITenantChangeService
implementation) for each tenant that is moved and it provides the oldDataKey
, newDataKey
, newFullTenantName
and tenantId
. This is done in an SQL Transaction so if either part fails all the changes are undone (see Multi-tenant configuration for more on this).
You can delete a AuthP's Tenant (but only if no AuthP users are linked to this tenant) using the DeleteTenantAsync(int tenantId)
method. This returns a IStatusGeneric<ITenantChangeService>
result. If the status is valid (i.e. no errors), then it provides the instance of the ITenantChangeService
you registered or updating to application data.
NOTE: If there are AuthP users are linked to this tenant the status returned will contain a list of errors containing the name of the AuthP user that is linked to this tenant.
Typically you would delete all the application data linked to this tenant and any linked to children using your implementation of the HandleTenantDeleteAsync
method (see Example4' ITenantChangeService
implementation). That is the safest way, but if you DON'T want to delete the linked application data you could change your implementation of the HandleTenantDeleteAsync
method to list the change in your ITenantChangeService
implementation and show that to the admin user.
NOTE: Deleting a tenant means the linked application data is inaccessible because the Tenant DataKey
has gone. BUT any all ready logged in users linked to the deleted Tenant will still have the DataKey claim and those users can still access the linked application data.
For this you use the UpdateTenantRolesAsync(int tenantId, List<string> newTenantRoleNames)
method, which also returns a status. This replaces all the tenant Roles in the tenant, but it doesn't call your ITenantChangeService
, as the change is only in the AuthP's database.
NOTE: You can find the current tenant Roles in a tenant via the GetRoleNamesForTenantsAsync
method in the IAuthTenantAdminService
service.
If you are using the UpdateTenantRolesAsync
you will find the tenant admin method called GetRoleNamesForTenantsAsync
, as this will provide you with the tenant Roles that can be added to a tenant.
- Intro to multi-tenants (ASP.NET video)
- Articles in date order:
- 0. Improved Roles/Permissions
- 1. Setting up the database
- 2. Admin: adding users and tenants
- 3. Versioning your app
- 4. Hierarchical multi-tenant
- 5. Advanced technique with claims
- 6. Sharding multi-tenant setup
- 7. Three ways to add new users
- 8. The design of the sharding data
- 9. Down for maintenance article
- 10: Three ways to refresh claims
- 11. Features of Multilingual service
- 12. Custom databases - Part1
- Videos (old)
- Authentication explained
- Permissions explained
- Roles explained
- AuthUser explained
- Multi tenant explained
- Sharding explained
- How AuthP handles sharding
- How AuthP handles errors
- Languages & cultures explained
- JWT Token refresh explained
- Setup Permissions
- Setup Authentication
- Startup code
- Setup the custom database feature
- JWT Token configuration
- Multi tenant configuration
- Using Permissions
- Using JWT Tokens
- Creating a multi-tenant app
- Supporting multiple languages
- Unit Test your AuthP app