Open Closed

How to enable ABP Commercial host tenant mapping feature in ABP commercial microservices solution? #5638


User avatar
1
kirotech created
  • ABP Framework version: v7.2
  • UI Type: Angular
  • Database System: EF Core (PostgreSQL)
  • Tiered (for MVC) or Auth Server Separated (for Angular): yes

Was not able to find any samples or documentation on how to enable url host tenant mapping feature in abp commercial microservices solution.

Maybe you can help?

I found samples repo, but there is no microservices sample available. Also tried to backward engineer feature enabling according tiered identity server solution, but it is not working.

Would appreciate your help on this.

Best Regards.


26 Answer(s)
  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    Hello kirotech,

    Could you please guide us how to reproduce this issue, share some steps to reproduce if possible.

    Thank you

  • User Avatar
    0
    kirotech created

    There is no documentation nor samples how to enable subdomain mapping to saas tenant feature on your abp commercial microservices solution.

    I probably could provide you with zip with the current state of work and maybe you can fix it?

    At the moment we getting authentication issues, also infinite login loop issue.

    If you provide documentation or sample for your abp commercial microservices solution it would be great.

    I found example for identity server tiered and openiddict monolitick solutions, but there is none for microservice commercial solution.

    I need your support on this.

  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    Hi

    please check this doc for resolving subdomain for tenant https://docs.abp.io/en/abp/latest/Multi-Tenancy#domain-subdomain-tenant-resolver

    you can place this code in BookstoreSharedHostingMicroservicesModule {yourprojectname}.Shared.Hosting.Microservices

    you can see the sample of ng tiered demo which will be similar to microservice. https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver/NG-TIERED

  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    Hello kirotech,

    Please do let us know if this solution has worked for you?

    Awaiting for your response.

    Thank You, Anjali

  • User Avatar
    0
    kirotech created

    I'm afraid to tell, but I'm not able to enable host mapping feature in abp commercial microservices solution.

    I already used sample your provided (https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver/NG-TIERED) to backward engineer configuration for abp commercial microservices solution, but it didn't work as i mentioned i started getting number of issues starting ssl issues ending openiddict configuration authentication issues.

    Could you please provide abp commercial microservices solution host mapping feature configuration documentation or sample?

    Let me know how you want to move forward.

    Best regards.

  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    Hi,

    can you explain your issue with a scenarios as i am not able clearly able to understand enable url host tenant mapping feature. The sample provided can work in microservices too but yes may differ in configuration.

    if you can provide a more detailed instructions of what you are trying to achieve we can provide some sample code related to that.

    Thanks.

  • User Avatar
    1
    kirotech created

    Yes i can provide more details.

    We do want to configure subdomain to tenant mapping feature in abp commercial microservices solution.

    Feature is described in the doc your provided: https://docs.abp.io/en/abp/latest/Multi-Tenancy?&_ga=2.146571124.1730784827.1693308814-2050754730.1671709604#domain-subdomain-tenant-resolver

    {0}.mydomain.com we want to map {0} to tenant in abp commercial microservices solution.

    There is no docs nor sample for that.

    So we tried to use your ng tiered sample from here: https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver/NG-TIERED

    It didn't work.

    Can you provide sample how to configure this abp feature in your abp commercial microservices solution?

    I can invite you in test repository where i have my current progress and you can apply your configuration sample directly or you going to provide it here?

    Best regards.

  • User Avatar
    1
    kirotech created

    Hello,

    Looks like your openiddict ng sample has issues.

    How to reproduce:

    1. Run https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver/OpenIddict/NG
    2. Login with host
    3. Create new tenant
    4. Go to https://newtenant.ng.abp.net:4200
    5. Click login
    6. You get open iddict redirect uri error:

    error:invalid_request error_description:The specified 'redirect_uri' is not valid for this client application. error_uri:https://documentation.openiddict.com/errors/ID2043

    How do you guys want to proceed on abp commercial microservices sample issues?

    Best regards.

  • User Avatar
    0
    kirotech created

    any update?

  • User Avatar
    0
    alper created
    Support Team Director

    check out https://community.abp.io/posts/how-to-use-domainbased-tenant-resolver-in-abp-with-angular-and-openiddict-v9y8da7v

  • User Avatar
    0
    kirotech created

    Hello alper, article helped to solve redirect_uri issue, but now I face angular problem where if you go to https://testtenant.ng.abp.net:4200 angular doesn't load because if he thinks that user is not authenticated no matter authserver returned valid token and issuer matching angular issuer environment config.

    I do have all this abp commercial microservices tenant subdomain mapping config in separate test repository which im ok to share with you if needed.

    I still need help with finishing this abp commercial microservices feature work.

  • User Avatar
    0
    LinchArnold created

    Hello alper, article helped to solve redirect_uri issue, but now I face angular problem where if you go to https://testtenant.ng.abp.net:4200 angular doesn't load because if he thinks that user is not authenticated no matter authserver returned valid token and issuer matching angular issuer environment config.

    I do have all this abp commercial microservices tenant subdomain mapping config in separate test repository which im ok to share with you if needed.

    I still need help with finishing this abp commercial microservices feature work.

    Hi, kirotech, if you have problem at the angular side, you can try the following steps, maybe it will work:

    1. Create a multi-tenancy-utils.ts file, this will be override the default implementation of ABP framework:
    import {
      ABP,
      CORE_OPTIONS,
      Environment,
      EnvironmentService,
      createTokenParser,
      getRemoteEnv,
    } from '@abp/ng.core';
    import { Injector } from '@angular/core';
    import clone from 'just-clone';
    
    const tenancyPlaceholder = '{0}';
    
    function getCurrentTenancyName(appBaseUrl: string): string {
      if (appBaseUrl.charAt(appBaseUrl.length - 1) !== '/') appBaseUrl += '/';
      const parseTokens = createTokenParser(appBaseUrl);
      const token = tenancyPlaceholder.replace(/[}{]/g, '');
      return parseTokens(window.location.href)[token]?.[0];
    }
    
    export function cleanPlaceholderFromHostUrl(injector: Injector) {
      const fn = async () => {
        const environmentService = injector.get(EnvironmentService);
        const options = injector.get(CORE_OPTIONS) as ABP.Root;
        environmentService.setState(options.environment as Environment);
        await getRemoteEnv(injector, options.environment);
        const baseUrl =
          environmentService.getEnvironment()['appBaseUrl'] ||
          environmentService.getEnvironment().application?.baseUrl ||
          '';
        const tenancyName = getCurrentTenancyName(baseUrl);
    
        if (!tenancyName) {
          /**
           * If there is no tenant, we still have to clean up {0}. from baseUrl to avoid incorrect http requests.
           */
          replaceTenantNameWithinEnvironment(injector, '', tenancyPlaceholder + '.');
          replaceTenantNameWithinEnvironment(injector, '', tenancyPlaceholder);
        }
    
        return Promise.resolve();
      };
    
      return fn;
    }
    
    function replaceTenantNameWithinEnvironment(
      injector: Injector,
      tenancyName: string,
      placeholder = tenancyPlaceholder
    ) {
      const environmentService = injector.get(EnvironmentService);
    
      const environment = clone(environmentService.getEnvironment()) as Environment;
    
      if (environment.application.baseUrl) {
        environment.application.baseUrl = environment.application.baseUrl.replace(
          placeholder,
          tenancyName
        );
      }
    
      if (environment.oAuthConfig?.redirectUri) {
        environment.oAuthConfig.redirectUri = environment.oAuthConfig.redirectUri.replace(
          placeholder,
          tenancyName
        );
      }
    
      if (!environment.oAuthConfig) {
        environment.oAuthConfig = {};
      }
      environment.oAuthConfig.issuer = (environment.oAuthConfig.issuer || '').replace(
        placeholder,
        tenancyName
      );
    
      environment.oAuthConfig.clientId = (environment.oAuthConfig.clientId || '').replace(
        placeholder,
        tenancyName
      );
    
      Object.keys(environment.apis).forEach(api => {
        Object.keys(environment.apis[api]).forEach(key => {
          environment.apis[api][key] = (environment.apis[api][key] || '').replace(
            placeholder,
            tenancyName
          );
        });
      });
    
      return environmentService.setState(environment);
    }
    
    
    1. Create domain-resolver.module.ts file:
    import { CommonModule } from '@angular/common';
    import { HttpClientModule } from '@angular/common/http';
    import { APP_INITIALIZER, Injector, NgModule } from '@angular/core';
    import { cleanPlaceholderFromHostUrl } from './multi-tenancy-utils';
    
    @NgModule({
      imports: [CommonModule, HttpClientModule],
      providers: [
        {
          provide: APP_INITIALIZER,
          multi: true,
          deps: [Injector],
          useFactory: cleanPlaceholderFromHostUrl,
        },
      ],
    })
    export class DomainResolverModule {}
    
    1. Import the DomainResolverModule in your AppModule:
    import { CoreModule } from '@abp/ng.core';
    import { GdprConfigModule } from '@volo/abp.ng.gdpr/config';
    import { SettingManagementConfigModule } from '@abp/ng.setting-management/config';
    import { HTTP_ERROR_HANDLER, ThemeSharedModule } from '@abp/ng.theme.shared';
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    import { CommercialUiConfigModule } from '@volo/abp.commercial.ng.ui/config';
    import { AccountAdminConfigModule } from '@volo/abp.ng.account/admin/config';
    import { AccountPublicConfigModule } from '@volo/abp.ng.account/public/config';
    import { AuditLoggingConfigModule } from '@volo/abp.ng.audit-logging/config';
    import { IdentityConfigModule } from '@volo/abp.ng.identity/config';
    import { LanguageManagementConfigModule } from '@volo/abp.ng.language-management/config';
    import { registerLocale } from '@volo/abp.ng.language-management/locale';
    import { SaasConfigModule } from '@volo/abp.ng.saas/config';
    import { TextTemplateManagementConfigModule } from '@volo/abp.ng.text-template-management/config';
    import { HttpErrorComponent, ThemeLeptonModule } from '@volo/abp.ng.theme.lepton';
    import { environment } from '../environments/environment';
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    import { APP_ROUTE_PROVIDER } from './route.provider';
    import { OpeniddictproConfigModule } from '@volo/abp.ng.openiddictpro/config';
    import { FeatureManagementModule } from '@abp/ng.feature-management';
    import { AbpOAuthModule } from '@abp/ng.oauth';
    import { ServiceWorkerModule } from '@angular/service-worker';
    import { APP_VALIDATION_PROVIDER } from './validation/app.validation.provider';
    import { DomainResolverModule } from './customization';
    
    @NgModule({
      declarations: [AppComponent],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        DomainResolverModule,
        CoreModule.forRoot({
          environment,
          registerLocaleFn: registerLocale(),
        }),
        AbpOAuthModule.forRoot(),
        ThemeSharedModule.forRoot({
          httpErrorConfig: {
            errorScreen: {
              component: HttpErrorComponent,
              forWhichErrors: [401, 403, 404, 500],
              hideCloseIcon: true,
            },
          },
        }),
        // Other import statements
      ],
      providers: [
        APP_ROUTE_PROVIDER,
        APP_VALIDATION_PROVIDER
      ],
      bootstrap: [AppComponent],
    })
    export class AppModule {}
    
  • User Avatar
    0
    kirotech created

    Thank you Linch, what problem you been solving by rewriting angular domain resolver? As i understand it supposed to work out of the box without rewriting it?

  • User Avatar
    0
    kirotech created

    Hello alper, Anjali_Musmade. Any update? I still need help with this abp commercial microservices solution feature.

  • User Avatar
    0
    kirotech created

    any update?

  • User Avatar
    0
    mindkfly created

    any update regarding this issue?

  • User Avatar
    0
    kirotech created

    any update?

  • User Avatar
    0
    gterdem created
    Senior .NET Developer

    Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?

    @mahmut.gundogdu Did we have updates on v7.4 based on this issue?

  • User Avatar
    0
    LinchArnold created

    Thank you Linch, what problem you been solving by rewriting angular domain resolver? As i understand it supposed to work out of the box without rewriting it?

    Hi, kirotech, I just updated the code of multi-tenancy-utils.ts , because it is work for datdv1 https://support.abp.io/QA/Questions/5650#answer-3a0d82ab-0969-e910-4824-cab59dc00e91

    Maybe you can try this to solve your problem. Hope it is work for you.

    import {
      ABP,
      CORE_OPTIONS,
      Environment,
      EnvironmentService,
      createTokenParser,
      getRemoteEnv,
    } from '@abp/ng.core';
    import { Injector } from '@angular/core';
    import clone from 'just-clone';
    
    const tenancyPlaceholder = '{0}';
    
    function getCurrentTenancyName(appBaseUrl: string): string {
      if (appBaseUrl.charAt(appBaseUrl.length - 1) !== '/') appBaseUrl += '/';
      const parseTokens = createTokenParser(appBaseUrl);
      const token = tenancyPlaceholder.replace(/[}{]/g, '');
      return parseTokens(window.location.href)[token]?.[0];
    }
    
    export function cleanPlaceholderFromHostUrl(injector: Injector) {
      const fn = async () => {
        const environmentService = injector.get(EnvironmentService);
        const options = injector.get(CORE_OPTIONS) as ABP.Root;
        environmentService.setState(options.environment as Environment);
        await getRemoteEnv(injector, options.environment);
        const baseUrl =
          environmentService.getEnvironment()['appBaseUrl'] ||
          environmentService.getEnvironment().application?.baseUrl ||
          '';
        const tenancyName = getCurrentTenancyName(baseUrl);
    
        if (!tenancyName) {
          /**
           * If there is no tenant, we still have to clean up {0}. from baseUrl to avoid incorrect http requests.
           */
          replaceTenantNameWithinEnvironment(injector, '', tenancyPlaceholder + '.');
          replaceTenantNameWithinEnvironment(injector, '', tenancyPlaceholder);
        }
    
        return Promise.resolve();
      };
    
      return fn;
    }
    
    function replaceTenantNameWithinEnvironment(
      injector: Injector,
      tenancyName: string,
      placeholder = tenancyPlaceholder
    ) {
      const environmentService = injector.get(EnvironmentService);
    
      const environment = clone(environmentService.getEnvironment()) as Environment;
    
      if (environment.application.baseUrl) {
        environment.application.baseUrl = environment.application.baseUrl.replace(
          placeholder,
          tenancyName
        );
      }
    
      if (environment.oAuthConfig?.redirectUri) {
        environment.oAuthConfig.redirectUri = environment.oAuthConfig.redirectUri.replace(
          placeholder,
          tenancyName
        );
      }
    
      if (!environment.oAuthConfig) {
        environment.oAuthConfig = {};
      }
      environment.oAuthConfig.issuer = (environment.oAuthConfig.issuer || '').replace(
        placeholder,
        tenancyName
      );
    
      environment.oAuthConfig.clientId = (environment.oAuthConfig.clientId || '').replace(
        placeholder,
        tenancyName
      );
    
      Object.keys(environment.apis).forEach(api => {
        Object.keys(environment.apis[api]).forEach(key => {
          environment.apis[api][key] = (environment.apis[api][key] || '').replace(
            placeholder,
            tenancyName
          );
        });
      });
    
      return environmentService.setState(environment);
    }
    
    
  • User Avatar
    0
    kirotech created

    Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?

    @mahmut.gundogdu Did we have updates on v7.4 based on this issue?

    I did not try no. I believe it supposed to work out of the box? My thought was because of lack of samples and documentation maybe i misconfigured feature.

    I created a separate github repo where i can reproduce the issue for this feature.

  • User Avatar
    0
    gterdem created
    Senior .NET Developer

    Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?

    @mahmut.gundogdu Did we have updates on v7.4 based on this issue?

    I did not try no. I believe it supposed to work out of the box? My thought was because of lack of samples and documentation maybe i misconfigured feature.

    I created a separate github repo where i can reproduce the issue for this feature.

    Please do share the github repository if its non-commercial or you can add galiperdem@gmail.com if it is commercial and private repository.

  • User Avatar
    0
    kirotech created

    Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?

    @mahmut.gundogdu Did we have updates on v7.4 based on this issue?

    I did not try no. I believe it supposed to work out of the box? My thought was because of lack of samples and documentation maybe i misconfigured feature.

    I created a separate github repo where i can reproduce the issue for this feature.

    Please do share the github repository if its non-commercial or you can add galiperdem@gmail.com if it is commercial and private repository.

    OK. I invited your email to the repo. Yes it is commercial product microservices architecture version. It is private repo.

  • User Avatar
    0
    kirotech created

    Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?

    @mahmut.gundogdu Did we have updates on v7.4 based on this issue?

    I did not try no. I believe it supposed to work out of the box? My thought was because of lack of samples and documentation maybe i misconfigured feature.

    I created a separate github repo where i can reproduce the issue for this feature.

    Please do share the github repository if its non-commercial or you can add galiperdem@gmail.com if it is commercial and private repository.

    any update?

  • User Avatar
    0
    gterdem created
    Senior .NET Developer

    We've created internal issue related to this. It will be fixed in the next minor or major patch based on Angular team's workload.

    I've refunded your credit.

    Thank you.

  • User Avatar
    0
    kirotech created

    We've created internal issue related to this. It will be fixed in the next minor or major patch based on Angular team's workload.

    I've refunded your credit.

    Thank you.

    Thank you very much for your help. Really appreciate it. Can you explain the problem a bit? I see you didn't event look at our repo. Maybe there is some temporary workaround while you release commercial fix?

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