How to set ApplicationContext.User in a background/non-HTTP execution context for multitenancy? #4833
Replies: 1 comment
-
|
This isn't a problem unique to CSLA. It is something people have to solve with angular, react, or any scenario where code running on the client device calls an API on a server, where there's no automatic authentication from the client to the server. The most common solutions are JWT tokens or API keys - either one of which generally gets passed from the client to the server via the HTTP header so aspnetcore middleware (not your business code - before your business code) can verify the inbound token before allowing the call to be processed on the server. Where your client code gets that token - now that's the trick. Usually a JWT comes from an oauth process, where the user logged into the app using some oauth workflow through Entra Id, Google, etc. If you are using API keys, those are usually created via some admin web site and provided to each client that calls the server. This isn't a great user experience in most cases, at least as compared to the more common oauth process. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Environment
Background
We have a multitenant Blazor application built on CSLA.NET. Our
TenantResolverreads the
TenantIdclaim fromApplicationContext.Userto scope every data portal callto the correct tenant. This works perfectly inside the Blazor UI —
ApplicationContext.Useris fully populated with the authenticated user's
ClaimsPrincipaland the tenant resolvescorrectly on every data portal call.
The Problem
We have a background processing component that runs outside the Blazor/HTTP pipeline.
It receives work requests via a REST API, processes them in its own execution context, and
calls back into our CSLA business objects through the data portal.
When our CSLA business objects execute inside this background component,
ApplicationContext.Useris an empty anonymousClaimsPrincipal— zero identities,zero claims. This causes our
TenantResolverto fail because it cannot find theTenantIdclaim, and all data portal calls are effectively unauthorised.
This makes sense — there is no
HttpContextin this background execution context, so CSLAhas nothing to populate
ApplicationContext.Userfrom automatically.What We Know About the Execution Context
circuit scope.
ApplicationContext.that processes it.
Our Current Approach
Since we control both sides, our current approach is to serialise the user's claims into
the JSON payload on the Blazor side and deserialise them on the background side, then
manually set
ApplicationContext.Userbefore making any data portal calls:Blazor side — serialise the ClaimsPrincipal into the request payload
We capture the bag in
OnInitializedAsyncwhile the Blazor circuit'sAuthenticationStateis still live:
And include it in every request payload sent to the background component:
Background component side — rehydrate and set ApplicationContext.User
Our Questions
Is manually setting
ApplicationContext.Userbefore data portal calls the correctand supported approach for a background/non-HTTP execution context in CSLA 8? Or is
there a more idiomatic way to inject the
ClaimsPrincipalfor the duration of abackground operation?
Is
ClaimsIdentitywith a customauthenticationTypestring sufficient for CSLA'sauthorization pipeline to treat the user as authenticated? We are currently using
"BackgroundTransfer"as the authentication type string. Will CSLA'sIsInRole,object-level authorization rules, and property-level authorization rules all behave
correctly given this identity?
Is there a CSLA-native mechanism we should be using instead — for example, a way
to configure a custom
IPrincipalprovider that theApplicationContextuses innon-HTTP scopes?
Are there any thread-safety concerns with setting
ApplicationContext.Userin abackground scope where multiple work items may be processing concurrently? Does each
DI scope get its own
ApplicationContextinstance, or is there shared state we needto be aware of?
Summary
The core question is: what is the correct CSLA pattern for propagating a known,
authenticated
ClaimsPrincipalinto a background processing scope that has its own DIcontainer but no HTTP context?
We want to make sure we are not working against the framework. Any guidance from the
community would be greatly appreciated.
Beta Was this translation helpful? Give feedback.
All reactions