We’re starting to migrate a rather large monolithic MVC 5 app to APIs and we have a question about how we’d solve our multi tenancy issue using ServiceStack.
In our MVC app we have a single Neo4j database and use a different sub-graph for each tenant. In graphs terms, a label is somewhat similar to a sql table. We prefix each label with our tenant id <tenant_key>_Topic
. Example: MATCH (person:tenant1_Person) RETURN person
.
We’re using forms authentication and we obtain tenant id from cookie and register our ITenant
instance from HTTPContext:
// MVC / Autofac tenant registration
builder
.Register(context => HttpContext.Current.User as ITenant)
.As<ITenant>()
.InstancePerLifetimeScope();
From there we can resolve the correct ITenant
for all user requests. This interface is weaved throughout the application.
In ServiceStack terms we’d like to do something similar. As we start building the APIs we’ll still have the MVC app, and as part of forms authentication, we’ll perform a secondary authentication against a ServiceStack API and probably obtain a JWT. We’d like to store the tenant key in this token and then calls to the secured APIs would need to extract the tenant key from the token and register an ITenant
in the API host.
public interface ITenant
{
string Key { get; set; }
}
public class Tenant : ITenant
{
public string Key { get; set; }
}
public class AppHost : AppHostBase
{
public AppHost() : base("demo", typeof(MyServices).Assembly) { }
// Configure your AppHost with the necessary configuration and dependencies your App needs
public override void Configure(Container container)
{
container.Register<ITenant>(c =>
{
var token = c.Resolve<???>
return new Tenant
{
Key = token.TenantKey
};
}).ReusedWithin(ReuseScope.Request);
}
}
But as you can see, I’m stuck at this point. I’m not sure what object is available to be in order to extract the tenant key. Can I access the request object? Or the user’s session? Once we’re passing JWTs can I access them in this context?
Another option for consideration is to register an empty ITenant
and then mutate this in a filter, setting ITenant.Key accordingly. But I’m not keen on mutating dependencies.