Open Closed

DomainTenantResolver for HttpApi.Host project in Tiered architecture #3413


User avatar
1
sh_erfan created

Hi Trying to implement DomanTenantResolver sample in my own project, everything is fine, except I cant use swagger in *HttpiApi.Host. Redirection from Identity back to api does not work. Neither with tenant available nor without tenant(host). I also tried to add OnChallenge event to JwtBearerOptions during configuration, but no success. I have no idea how to implement this. P.S: In your sample resolver, I cant event authorize with "web.getap.com:1234/swagger". In other words, api is out of reach.

Any help would be appreciated

  • ABP Framework version: 5.2.1
  • UI type: MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): yes

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

    hi

    How can I reproduce the problem via DomanTenantResolver sample?

  • User Avatar
    0
    sh_erfan created

    Hi there

    First simple scenario:

    • Head to DomainTenantResolver/MVC-TIERED
    • Add BookStore_Swagger client to appsettings.json in DbMigrator:
    "IdentityServer": {
        "Clients": {
          "BookStore_Web": {
            "ClientId": "BookStore_Web",
            "ClientSecret": "1q2w3e*",
            "RootUrl": "https://{0}.web.getabp.net:44303"
          },
          "BookStore_Swagger": {
            "ClientId": "BookStore_Swagger",
            "ClientSecret": "1q2w3e*",
            "RootUrl": "https://{0}.api.getabp.net:44302"
          }
        }
    
    • Add BookStore_Swagger client to IdentityDataSeedContributor.cs
    //Web Client
    var webClientId = configurationSection["BookStore_Web:ClientId"];
    if (!webClientId.IsNullOrWhiteSpace())
    {
    	var webClientRootUrl = configurationSection["BookStore_Web:RootUrl"].EnsureEndsWith('/');
    
    	/* BookStore_Web client is only needed if you created a tiered
    	 * solution. Otherwise, you can delete this client. */
    
    	await CreateClientAsync(
    		name: webClientId,
    		scopes: commonScopes,
    		grantTypes: new[] { "hybrid" },
    		secret: (configurationSection["BookStore_Web:ClientSecret"] ?? "1q2w3e*").Sha256(),
    		redirectUri: $"{webClientRootUrl}signin-oidc",
    		postLogoutRedirectUri: $"{webClientRootUrl}signout-callback-oidc",
    		frontChannelLogoutUri: $"{webClientRootUrl}Account/FrontChannelLogout",
    		corsOrigins: new[] { webClientRootUrl.RemovePostFix("/") }
    	);
    }
    
    // Swagger Client
    var swaggerClientId = configurationSection["BookStore_Swagger:ClientId"];
    if (!swaggerClientId.IsNullOrWhiteSpace())
    {
    	var swaggerRootUrl = configurationSection["BookStore_Swagger:RootUrl"].TrimEnd('/');
    
    	await CreateClientAsync(
    		name: swaggerClientId,
    		scopes: commonScopes,
    		grantTypes: new[] { "authorization_code" },
    		secret: (configurationSection["Recruitans_Swagger:ClientSecret"] ?? "1q2w3e*").Sha256(),
    		requireClientSecret: false,
    		redirectUri: $"{swaggerRootUrl}/swagger/oauth2-redirect.html",
    		corsOrigins: new[] { swaggerRootUrl.RemovePostFix("/") }
    	);
    }
    
    • Run DbMigrator
    • Run multiple projects (ids, web,api)
    • Open swagger https://api.getabp.net:44302/swagger/index.html and try to authorize using host admin user. it fails on redirection.

    This is the initial scenario that I cant use swagger api.

  • User Avatar
    1
    maliming created
    Support Team Fullstack Developer

    hi src/Acme.BookStore.IdentityServer/appsettings.json

    Add https://api.getabp.net:44302 to CorsOrigins of IdentityServer project.

    "CorsOrigins": "https://*.api.getabp.net,https://*.web.getabp.net,https://api.getabp.net:44302"

    I will update the sample.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    https://github.com/abpframework/abp-samples/commit/4daebdd8a3b32b7fb47ac05e2ff69b834766e89b

  • User Avatar
    0
    sh_erfan created

    Actually this worked for me "https://*.api.getabp.net,https://*.web.getabp.net,https://api.getabp.net:44302" This is solution for host user authorization.

    Now, the second part. How should we handle https://tenant1.api.getabp.net:44302/swagger/index.html for tenant1?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    How should we handle https://tenant1.api.getabp.net:44302/swagger/index.html for tenant1?

    What do you mean?

  • User Avatar
    0
    sh_erfan created

    I want to implement resolver for web api project:

    Configure<AbpTenantResolveOptions>(options =>
    {
        options.AddDomainTenantResolver("{0}.api.getabp.net:44302");
    });
    

    Then, I want to go to https://tenant1.api.getabp.net:44302/swagger/index.html When authorizing, I want to be automatically be directed to https://tenant.ids.getabp.net:44301 After that, redirect back to https://tenant1.api.getabp.net:44302/swagger/index.html Now, my swagger client is authorized and the active tenant is tenant1 Hence, current tenant id will tenant1 id. Just like web project.

    Hope you understand

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    I don't know if swagger supports custom authorize urls, I'll check.

  • User Avatar
    1
    maliming created
    Support Team Fullstack Developer

    Can you try this?

    
    services.AddAbpSwaggerGenWithOAuth(
    services.AddTransient<SwaggerGenerator>();
    services.Replace(ServiceDescriptor.Transient<ISwaggerProvider, MySwaggerGenerator>());
    
    using System;
    using Microsoft.OpenApi.Models;
    using Swashbuckle.AspNetCore.Swagger;
    using Swashbuckle.AspNetCore.SwaggerGen;
    using Volo.Abp.MultiTenancy;
    
    namespace MyCompanyName.MyProjectName.Web;
    
    public class MySwaggerGenerator : ISwaggerProvider
    {
        private readonly SwaggerGenerator _innerSwaggerGenerator;
        private readonly SwaggerGeneratorOptions _options;
        private readonly ICurrentTenant _currentTenant;
    
        public MySwaggerGenerator(SwaggerGenerator innerSwaggerGenerator, SwaggerGeneratorOptions options, ICurrentTenant currentTenant)
        {
            _innerSwaggerGenerator = innerSwaggerGenerator;
            _options = options;
            _currentTenant = currentTenant;
        }
    
        public OpenApiDocument GetSwagger(string documentName, string host = null, string basePath = null)
        {
            foreach (var securityScheme in _options.SecuritySchemes)
            {
                if (securityScheme.Value.Flows.AuthorizationCode != null && _currentTenant.IsAvailable)
                {
                    securityScheme.Value.Flows.AuthorizationCode.AuthorizationUrl = new Uri(securityScheme.Value.Flows.AuthorizationCode.AuthorizationUrl.ToString().Replace("ids", $"{_currentTenant.Name}.ids"));
                    securityScheme.Value.Flows.AuthorizationCode.TokenUrl = new Uri(securityScheme.Value.Flows.AuthorizationCode.TokenUrl.ToString().Replace("ids", $"{_currentTenant.Name}.ids"));
    
                }
            }
    
            return _innerSwaggerGenerator.GetSwagger(documentName, host, basePath);
        }
    }
    
    
    
  • User Avatar
    0
    sh_erfan created

    Thanks a lot This solved the problem Better to update sample to avoid future duplicate questions

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
Do you need assistance from an ABP expert?
Schedule a Meeting
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v9.3.0-preview. Updated on April 16, 2025, 12:13