-
Notifications
You must be signed in to change notification settings - Fork 162
Update claims on tenant change
The AuthP's multi-tenant code contains two commands that change the user's tenant claim(s). They are:
- Move sub-tenant (hierarchical) - see the Moving a hierarchical Tenant section of the Hierarchical Multi-Tenant document.
- Move database (sharding). See the Sharding: Move Tenant to database document.
When one of these commands are run, then the user's tenant claim(s) are now out of date. This document describes the optional code that can update a user's tenant claim(s) on a change of a tenant data is changed. Example 4 contains the "update on change" feature and code shown in this document comes from there.
The diagram below explains this feature works:
NOTE: At this time this approach doesn't work for applications using JWT Bearer Token. If you need this to work with JWT Bearer Tokens, then raise a issue about this and I can suggest some things you could do to make it work with JWT Bearer Tokens.
This is an optional feature, so you need to register the various services for this feature. The code below shows the three parts you need to add to the ASP.NET Core Program class
. Once all the code is registered, then it automatically updates a tenant's claims on a change.
To change a user's claims you need to intercept the Authorization stage and run some code that will update the user's claims an create a new Authentication cookie. The code below shows how to do this when using individual user accounts authentication - if you are using other approaches like OAuth2 or OpenId, then see this section on one of my articles.
builder.Services.ConfigureApplicationCookie(options =>
{
//all the logged-in users will have their claims checked
options.Events.OnValidatePrincipal =
TenantChangeCookieEvent.UpdateClaimsIfSomethingChangesAsync;
});
NOTE: You can see the code that updates the user's claims when using individual user accounts authentication in the TenantChangeCookieEvent.
The "update on change" feature needs to set a value to say that something has changed at time T. As this value has to be read on every HTTP request it needs to be fast, and in version 3.4.0 I used my FileStore distributed cache library which has read times of ~25 ns. The code below registers the FileStore cache in your Program class.
//This is used to set app statue as "Down" and tenant as "Down",
//plus handling a tenant DataKey change that requires an update of the user's claims
builder.Services.AddDistributedFileStoreCache(options =>
{
options.WhichVersion = FileStoreCacheVersions.Class;
}, builder.Environment);
We also want the FileStore cache to work like a database, that is the data should not be lost on the redeployment of the application. By default if the computer that deploys your application has a json file exists with the same name as the FileStore cache file it would overwrite the FileStore cache file. You can make sure this happens by adding a "copy never" command to the ASP.NET Core .csprog file - see the extra <ItemGroup>
part to be added.
<ItemGroup>
<Content Update="Example4CacheFileStore.Production.json">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Content>
</ItemGroup>
NOTE: The FileStore distributed cache (in database mode) is also used in the "Down for maintenance" feature.
The code below registers the two services to manage the "update on change" feature. Note that the TenantKeyOrShardChangeService
class detect changes to the Tenant
's properties that effect a tenant user's data claim(s), but this could detect any database
//triggers the "update claims on a change" feature
builder.Services.AddSingleton<IDatabaseStateChangeEvent,
TenantKeyOrShardChangeService>();
//used for "update claims on a change" feature
builder.Services.AddSingleton<IGlobalChangeTimeService,
GlobalChangeTimeService>();
Once you have registered all three listed the update is triggered by the database change. That is, a change to the Tenant's DataKey or Sharding DatabaseInfoName properties will cause every logged-in user with claims older than the last database change will be updated to the correct claims.
You must register AddGlobalChangeTimeClaim
claim, which contains the DateTime when the claims were updated. If you forget to add this claim your application will work, but will be VERY SLOW because user's claims will be recalculated on every HTTP request.
The code below shows how to register the AddGlobalChangeTimeClaim
claim.
builder.Services.RegisterAuthPermissions<Example4Permissions>(options =>
{
options.TenantType = ...
})
//... other AuthP register methods left out
.RegisterAddClaimToUser<AddGlobalChangeTimeClaim>()
- 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