To enforce authorization in my applications, I usually decorate every domain service with an authorization decorator, that takes some service authorizer to perform authorization.
For instance: CarService : ICarService
is decorated with CarServiceAuthorizationDecorator : ICarService
that gets an ICarServiceAuthorizer
injected to perform authorization and when successfull, calls the actual CarService
.
This setup has served me well, except one little detail that has always bugged me: I have to pass some Token
with every single call to ICarService
, because the authorizer needs it. Even if it doesn't, then the CarService
may call a CarOwnerShipService
that is again decorated with an authorizer, that may need it as well. A lot of Tokens
everywhere.
The only way that I can come up with, to fix this, is to inject some ITokenProvider
into the CarServiceAuthorizer
that acts like a storage device: You put in the token at the start, and it keeps it along the way for any service that gets it out, so it doesn't need to be passed with every method call.
For this to work, the lifetime of that ITokenProvider must be the same as the lifetime of the thread. And not only that: newly spawned threads will need the token too.
So my question is: Is there a way to scope the lifetime of my ITokenProvider to a thread, including child threads, in .NET DI?
(AddScoped
doesn't seem to help me, I think, because not all threads in my application start with a web request. Also, I have had major issues with newly spawned threads with AddScoped
, that would lose their state.)
CodePudding user response:
that acts like a storage device: You put in the token at the start, and it keeps it along the way for any service that gets it out, so it doesn't need to be passed with every method call.
AddScoped
doesn't seem to help me, I think, because not all threads in my application start with a web request.
Based on the first quote I would argue that scoped ITokenProvider
is exactly what you need (though without seeing the actual code it is more of a guess). Just create a scope when needed and use it, and do not rely on threading (i.e. you can spawn several threads using the same scope). Something along this lines:
IServiceProvider serviceProvider = ...;
using (var serviceScope = serviceProvider.CreateScope())
{
var tokenService = serviceProvider.GetRequiredService<ITokenProvider>(); // or even split `ITokenProvider` into two interfaces
tokenService.SetToken("");
// resolve and call something using the token somewhere down the pipeline ...
// Maybe even with Task.Run(...)
}