简体   繁体   中英

Simple Injector get current principal in WebAPI using OWIN

Is there anyway to access the current principal and before the request gets to the controller using Simple Injector? I am using OWIN and Asp.net identity.

I have a DbContext that I inject into my controllers, but this context will get it's connection string based off the authenticated user. This is what I have so far,

container.RegisterWebApiRequest<TenantDbContext>();
container.RegisterWebApiRequest<ITenantConnectionStringProvider>(() => new TenantConnectionStringProvider(container));

Then in my TenantConnectionStringProvider I have this,

var request = container.GetCurrentHttpRequestMessage();
var principal = request.GetRequestContext().Principal as ClaimsPrincipal;

But the principal has no claims. I realized the claims are only available after the controller has been created. Does this mean it's just not possible because this step comes before the controller is created?

Edit: This is basically what the rest of the code does:

WebApi Controller

    public CampaignsController(TenantDbContext context, ILog log)
    {
        this.campaignService = campaignService;
        this.log = log;
    }

Tenant context(just inherits from DbContext from EF):

    public TenantDbContext(ITenantConnectionStringProvider provider)
        : base(provider.GetConnectionString())
    {
    }

After messing around a bit, I was able to do this, but it feels very hacky.. I added an OWIN middleware that happens after authentication. I'm not sure why but I have all the authenticated users information here, but when it goes to the TenantConnectionStringProvider, none of this info is available on the HttpRequestMessage.

        app.Use(async (context, next) =>
        {
            using (container.BeginExecutionContextScope())
            {
                CallContext.LogicalSetData("Claims", context.Authentication.User.Claims);
                var request = (OwinRequest)context.Request;
                await next();
            }
        });

Then in my TenantConnectionStringProvider I just did this,

    public string GetConnectionString()
    {
        var context = (IEnumerable<Claim>)CallContext.LogicalGetData("Claims");
        return "test";//get claim from context to get the connection string
    }

You can register a Func<ClaimsPrincipal> (factory) and inject it to your TenantConnectionStringProvider class :

public class TenantConnectionStringProvider : ITenantConnectionStringProvider
{
    private readonly Func<ClaimsPrincipal> _claimsPrincipalFactory;
    public TenantConnectionStringProvider(Func<ClaimsPrincipal> claimsPrincipalFactory)
    {
        _claimsPrincipalFactory = claimsPrincipalFactory;            
    }

    public void TestMethod()
    {
        // Access the current principal
        var principal = _claimsPrincipalFactory();
    }
}

Registrations should look like that (not sure...):

// Register your types, for instance using the scoped lifestyle:
container.RegisterSingleton<Func<ClaimsPrincipal>>(() =>
{
    // Not sure of which one to use.
    //return (ClaimsPrincipal)HttpContext.Current.User;
    //return (ClaimsPrincipal)Thread.CurrentPrincipal;
    return (ClaimsPrincipal)Context.User;
});
container.RegisterWebApiRequest<ITenantConnectionStringProvider, TenantConnectionStringProvider>();

Does this mean it's just not possible because this step comes before the controller is created?

Definitely the way you've created it. I'm not completely familar with the but I bet using Lazy<> might be of benefit:

var request = container.GetCurrentHttpRequestMessage();
var principal = new Lazy<ClaimsPrincipal>(() => 
  {
    return request.GetRequestContext().Principal as ClaimsPrincipal;
  });

Not tested, but when you actually need the principal value (i'm assume sometime later, in a different method in the same class) you can use principal.Value and it would then run and retrieve your ClaimsPrincipal . Granted these are huge assumptions because there is no code to see how everything is wired up. If you can provide how you get your connectionstring for the dbcontext (how that is all wired up) I might be able to give you a complete solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM