Skip to content

Hierarchical Multi Tenant

Jon P Smith edited this page Nov 7, 2023 · 6 revisions

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.

Hierarchical multi-tenant example

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.

Explaining the hierarchical multi-tenant features

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.

Creating a new hierarchical Tenant

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.

Adding / changing a Tenant to an AuthP user

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.

AddChangeUsersHierarchicalTenant

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.

Getting access to existing AuthP Tenants information

There are five method for obtaining AuthP Tenants data:

  • QueryTenants(), which returns a IQueryable<Tenant> result. This allows you to list all the possible tenants.
  • QueryEndLeafTenants(), which returns a IQueryable<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 an IStatusGeneric<Tenant> result. If the status is valid, then it returns the Tenant with the given tenantId plus its Parent tenant. This is useful for getting information to show prior to an update or delete.
  • GetHierarchicalTenantChildrenViaIdAsync(int tenantId), which returns a List<Tenant> result, which holds all the tenants linked to the tenant with the given tenantId. This is useful to display what other tenants will be deleted if the tenant with tenantId is deleted.
  • The IAuthUsersAdminService service has a GetAllTenantNamesAsync() method which returns a List<string> result. This is useful for create dropdown lists as shown in the screenshot above.

Updating a hierarchical Tenant name

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.

Moving a hierarchical Tenant

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:

Hierarchical Move Example

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).

Deleting a hierarchical tenant

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.

Changing the tenant Roles in the tenant

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.

Articles / Videos

Concepts

Setup

Usage

Admin

SupportCode

Clone this wiki locally