Open Closed

TenantConnectionString not changed on CustomTenantResolver using AccessToken #1445


User avatar
0
Mohammad created

Hello

public class AccessTokenTenantResolver : HttpTenantResolveContributorBase
    {
        public override string Name => "AccessToken";

        protected override Task<string> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext)
        {
           
            string accessCode = httpContext.Request.Headers["Authorization"];

            if (!string.IsNullOrEmpty(accessCode))
            {
                var token = accessCode.Split(" ")[1];
                var tokenHandler = new JwtSecurityTokenHandler();
                var tokens = tokenHandler.ReadJwtToken(token);
                var client_id = tokens.Claims.FirstOrDefault(x => x.Type == "client_id").Value;
                var scopes = tokens.Claims.FirstOrDefault(x => x.Type == "scope").Value;
                
            }

            return Task.FromResult("39fb7b60-0ba6-8109-70b1-a049e5f25575");

            //throw new NotImplementedException();
        }
    }

I have this custom tenant resolver which resolves the tenant based on the client_id from the AccessToken. The Current Tenant Information is populated properly however the connection string of the tenant is not changed based on the connection string set in the database.


23 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    n. The Current Tenant Information is populated properly

    Do you mean the ICurrentTenant is changed? Can you confirm?

    the connection string of the tenant is not changed based on the connection string set in the database.

    Can you explain in details?

  • User Avatar
    0
    Mohammad created
    • Do you mean the ICurrentTenant is changed? Can you confirm? Yes. It shows the proper tenant

    • The connection string of the tenant is not changed based on the connection string set in the database. I am using seperate database per tenant. The connection string is stored in the database for each tenant database. While running the query the connection string is not taken from the database.

    E.g The Identity Server Project Has seperate connection strings for each module

    "ConnectionStrings": {
        "Default": "Host=xxx.xxx.xxx.xxx;Port=5432;Database=Tenant1;Username=postgres;Password=xxxxxx;",
        "AbpIdentityServer": "Host=xxx.xxx.xxx.xxx;Port=5432;Database=Identity;Username=postgres;Password=xxxxxx;",
        "AbpIdentity": "Host=xxx.xxx.xxx.xxx;Port=5432;Database=Identity;Username=postgres;Password=xxxxxx;",
    }
    
    

    and if I set a Default Connection String for the Tenant in the database (AbpTenantConnectionStrings Table) When I Try to login to this tenant the Identity Server throws errors

    Npgsql.PostgresException (0x80004005): 42P01: relation "AbpUsers" does not exist

    For some reason the abp tries to find the AbpUsers table in Tenant1 Database Instead of searching for it in Identity Database.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you copy the code of MultiTenantConnectionStringResolver to debug to see what happend?

    https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantConnectionStringResolver.cs

  • User Avatar
    0
    Mohammad created

    Hi

    The current tenant id is null in MultiTenantConnectionStringResolver even after the custom tenant resolver has executed also it is null when the api is executing.

    I am on version 4.2.2

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    HI

    That's why I need you to confirm the ICurrentTenant .

    So your AccessTokenTenantResolver is not working.

    The framework has some build in TenantResolver https://docs.abp.io/en/abp/latest/Multi-Tenancy#determining-the-current-tenant

    CurrentUserTenantResolveContributor: Gets the tenant id from claims of the current user, if the current user has logged in. This should always be the first contributor for the security.

  • User Avatar
    0
    Mohammad created

    I have disabled AccessTokenTenantResolver and trying to access the application it still cannot determine the tenant connection string from the database.

    It only happens when a connection string for a tenant is set in the database.

    Can you please do a remote session and check. I have been facing this issue since i upgraded to 4.2.2

    Thanks

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    I have disabled AccessTokenTenantResolver and trying to access the application it still cannot determine the tenant connection string from the database. It only happens when a connection string for a tenant is set in the database.

    hi

    Can you check the MultiTenantConnectionStringResolver ? I also check it if we remotely.

  • User Avatar
    0
    Mohammad created

    I have checked MultiTenantConnectionStringResolver.

    I'll share zoom details on email.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi Mohammad

    I have checked. This is by design.

    Your tenant's default connection string should contain the module tables that support multi-tenancy.

    The tenant's default connection string means default, So it will no longer look for the connection string on the host side.

    If you don't want this behavior, you can customize MultiTenantConnectionStringResolver for some special cases of your.

  • User Avatar
    0
    Mohammad created

    Hi Ma

    Can you provide a sample code to acheive this using MultiTenantConnectionStringResolver ?

    Thanks

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    These few lines of code return the tenant's default connection string, you can call return await base.ResolveAsync(connectionStringName); for some situations, which will get the host's connection string.

    https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantConnectionStringResolver.cs#L76-L79

  • User Avatar
    0
    Mohammad created

    Hi Ma.

    I was debugging the same. There is a very wierd behaviour with the MultiTenantConnectionStringResolver code.

    For 1 request it asks to resolve AbpPermissionManagement, AbpAuditLogging on the 2nd request it Asks to resolve only AbpAuditLogging for the same page request.

    I was trying a workaround. where I set a custom name for the tenant connection string. So when the connectionstring is required by the dbcontext it will try to resolve using the MultiTenantConnectionStringResolver.

    I have two modules which work on multitenany

    1. ProductManagement
    2. Intelligence

    So according the the code behaviour It should try to resolve connection string for ProductManagement and Intelligence. But it only tries to resolve ProductManagement.

    This thread also has the same issues https://support.abp.io/QA/Questions/335/Steps-to-create-Single-Deployment---Multiple-Database-Multi-Tenant-Solution

    If you can connect to me remotely I can show you the debug.

    Thanks

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    For 1 request it asks to resolve AbpPermissionManagement, AbpAuditLogging on the 2nd request it Asks to resolve only AbpAuditLogging for the same page request.

    I think this is because the Permissions are cached. So we don't need read it from db for 2nd request.

    So according the the code behaviour It should try to resolve connection string for ProductManagement and Intelligence. But it only tries to resolve ProductManagement.

    It will only be triggered when Intelligence-related repositories are used and the _currentTenant.Id not be null.

    Your entity also need IsMultiTenant https://github.com/abpframework/abp/blob/c4e92a3431787b1a6727a615768a7a2906a9ba69/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs#L52

  • User Avatar
    0
    Mohammad created

    For 1 request it asks to resolve AbpPermissionManagement, AbpAuditLogging on the 2nd request it Asks to resolve only AbpAuditLogging for the same page request.

    I think this is because the Permissions are cached. So we don't need read it from db for 2nd request.

    So according the the code behaviour It should try to resolve connection string for ProductManagement and Intelligence. But it only tries to resolve ProductManagement.

    It will only be triggered when Intelligence-related repositories are used and the _currentTenant.Id not be null.

    Your entity also need IsMultiTenant

    I am using Single database per tenant.

    1. Should My entities implement IMultitenant?

    https://github.com/abpframework/abp/blob/c4e92a3431787b1a6727a615768a7a2906a9ba69/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs#L52

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    The entity inherits IMultiTenant which means it is multi-tenant, and will try to get the connection string of the tenant.

  • User Avatar
    0
    Mohammad created

    The entity inherits IMultiTenant which means it is multi-tenant, and will try to get the connection string of the tenant.

    In v4.0 It was working without Inheriting IMultiTenant https://github.com/abpframework/abp/blob/rel-4.0/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs

    I think its a change that has been made in the new version?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    See https://github.com/abpframework/abp/pull/7509

  • User Avatar
    0
    Mohammad created

    So what would you suggest in my case for Seperate database per tenant?

    1. Should I inherit all entities with IMultiTenant? If I do this then I'll have to store the tenantid in each table? Which doesnt serve the purpose of having separate databases per tenant.
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    You should implement the IMultiTenant interface for your entities to make them multi-tenancy ready.

    https://docs.abp.io/en/abp/latest/Multi-Tenancy

  • User Avatar
    0
    Mohammad created

    Thanks

  • User Avatar
    0
    Mohammad created

    Hello

    I am getting this error when I try to resolve a repository using ServiceProvider.GetService in CustomTenantResolver

    Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi Mohammad

    Please create a new question, Thanks

  • User Avatar
    0
    Mohammad created

    Hi Maliming

    Its belonging to the customtenantresolver

Made with ❤️ on ABP v9.1.0-preview. Updated on November 11, 2024, 11:11