I am currently trying my hand at a microservices architecture for the first time, and I am looking to put together a multi-tenant application built on a this architecture. Tenants are created with their own subdomain, and the tenant owner can create further user accounts linked to that tenant

I currently have the identity api set up, and was thinking of composing the rest a bit like the following:

enter image description here

The Gateways are intended to be implemented as Backend-For-Frontend and would aggregate data as necessary to satisfy the client request to that gateway.

In the identity API, I use the SaasKit middleware to check the subdomain and get tenant details. I was wondering what would be the best approach to apply this tenant discovery across the rest of the services? I am wary of creating a coupling that would undermine the autonomy of microservices. Would I do my tenant discovery in the gateways and pass the tenant ID to the microservices when requests are made to the services, should I be holding local copies of tenant information in each service, or should I use SaasKit in each service and call out to the identity API in each service to get tenant information if its not already cached?

EDIT: To add some context on to how tenants are created; The tenants are created via an API call from a separate system which provides a JWT created by a central authentication service separate to this. Users are also created this way, but the users created here are authenticated here rather than the 'other' authentication service

有帮助吗?

解决方案 2

The implementation I used relied on SaaS kit purely for the Identity service to use the domain detected for authenticating against the correct tenant. From when I the JWT passed to the the gateway and in turn to the underlying services contained a tid field for the tenant ID

I then used that in my Entity Framework context. As an example:

public class MyDbContext : DbContext
{
    private readonly ITenantProvider _tenantProvider;
    private Guid? TenantId => _tenantProvider.GetTenantId();

    public MyDbContext(DbContextOptions<MyDbContext> options, ITenantProvider tenantProvider) : base(options)
    {
        _tenantProvider = tenantProvider;
    }

    public DbSet<MyModel> MyModels { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<MyModel>().HasQueryFilter(s => TenantId != null && s.TenantId == TenantId);
    }
}

And implemented by ITenantProvider like so. I was checking for both tid and the url for tenantid as the default for JWT is to use the URL if you add a tid property, as described here:

public class HttpContextTenantProvider : ITenantProvider
    {
        private readonly HttpContext _httpContext;

        public HttpContextTenantProvider(IHttpContextAccessor httpContextAccessor)
        {
            _httpContext = httpContextAccessor.HttpContext;
        }

        public Guid? GetTenantId()
        {
            if (_httpContext?.User == null)
            {
                return null;
            }

            var tenantIdClaim = _httpContext.User.Claims.FirstOrDefault(c => c.Type.Equals("http://schemas.microsoft.com/identity/claims/tenantid", StringComparison.InvariantCultureIgnoreCase) || c.Type.Equals("tid", StringComparison.InvariantCultureIgnoreCase));

            if (tenantIdClaim == null)
            {
                return null;
            }

            return Guid.Parse(tenantIdClaim.Value);
        }
    }

其他提示

Since you are using micro-services I am guessing that you are using token based authentication/authorization which means that you have a signed token in which you can securely pass data from a client to a service and from service to service to authorize requests. If not I would suggest to do so because this will enable you to:

  • Capture/Recognize the tenant information in the API Gateway through the identity service. The identity service would return the auth token which will include the tenant id.

  • There is no need to keep local copies of tenant ids or make extra calls to the identity server since the tenant id is already in the token

  • In order to acquire specific tenant configurations/access rights, caching may be required to cache data per tenant for quick retrieval.

许可以下: CC-BY-SA归因
scroll top