TedS
TedS

Reputation: 141

How to add User to Role using ASP.NET Core Identity framework services In multi-tenancy architecture

We are implementing Multi-tenant architecture for our project.

  1. I have created User using userManager.CreateAsync(user, register.Password);
  2. Then Created Admin role using await roleManager.CreateAsync(new ApplicationRole("Admin", ParentCompanyId))
  3. Then I am trying to add "Admin" role to created User using userManager.AddToRoleAsync(user, roleAdmin);

since our application is for multiple tenant and having Tenant wise Admin role in AspNetRoles table so AddToRoleAsync() is failing caz its not getting correct Admin role or having ambigious "Admin" role in AspNetRoles table so throwing below exception. so can anyone guide me please how to add correct role to particular user. Since identity framework don't have any service to assign Role to user using RoleID, it would have been simpler. Can anyone give solution for this approach or can suggest correct approach to add user to roles.

How to add User to Role using asp.net core Identity Framework services In Multi tenancy Architecture. I am not able to add user to Admin role tenantwise using userManager.AddToRoleAsync(),

Receiving Below Exception on executing userManager.AddToRoleAsync(User,Role) method

"System.InvalidOperationException: Enumerator failed to MoveNextAsync. at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9.IsInRoleAsync(TUser user, String normalizedRoleName, CancellationToken cancellationToken) at Microsoft.AspNetCore.Identity.UserManager`1.AddToRoleAsync(TUser user, String role) at Salon.Controllers.AccountController.SignUp(RegisterViewModel register) in C:\Users\Controllers\AccountController.cs:line 78"

Upvotes: 3

Views: 1331

Answers (1)

Marcel
Marcel

Reputation: 1109

The way to do is to overwrite the default RoleStore and filter the roles by tenant in the custom RoleStore.

For this solution i'm assuming you are using SaasKit to resolve your tenants and your custom IdentityRole has a Tenant property.

If you look at the source code of UserManager.AddToRoleAsync they just use the provided RoleStore.

So if you look at the source code of the RoleStore, you can see all queries are done via Roles property. By adding a filter of tenants there you can always get the relevant Role assuming the tenant is resolved.

So the custom RoleStore:

public class TenantRoleStore : RoleStore<ApplicationRole<string>>
{
    private readonly TenantContext<Tenant> _tenantContext;

    public TenantRoleStore(
        CustomDbContext context,
        TenantContext<Tenant> tenantContext,
        IdentityErrorDescriber describer = null)
        : base(context, describer)
    {
        _tenantContext = tenantContext;
    }

    public override IQueryable<ApplicationRole<string>> Roles => base.Roles.Where(r => r.Tenant.Id == _tenantContext.Tenant.Id);
}

In the startup just add it where you configure Identity:

services.AddIdentity()
    .AddRoleStore<TenantRoleStore>(); // <- add this

Upvotes: 4

Related Questions