简体   繁体   English

Simple Injector使用OWIN在WebAPI中获取当前主体

[英]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? 无论如何都要访问当前主体并在请求使用Simple Injector进入控制器之前? I am using OWIN and Asp.net identity. 我正在使用OWIN和Asp.net身份。

I have a DbContext that I inject into my controllers, but this context will get it's connection string based off the authenticated user. 我有一个DbContext,我注入到我的控制器中,但是这个上下文将根据经过身份验证的用户获取它的连接字符串。 This is what I have so far, 这是我到目前为止,

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

Then in my TenantConnectionStringProvider I have this, 然后在我的TenantConnectionStringProvider中我有这个,

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 WebApi控制器

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

Tenant context(just inherits from DbContext from EF): 租户上下文(仅从EF的DbContext继承):

    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. 在搞砸了一下后,我能够做到这一点,但感觉非常hacky ..我添加了一个在验证后发生的OWIN中间件。 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. 我不确定为什么,但我在这里有所有经过身份验证的用户信息,但是当它转到TenantConnectionStringProvider时,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, 然后在我的TenantConnectionStringProvider中,我就这样做了,

    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 : 您可以注册一个Func<ClaimsPrincipal> (工厂)并将其注入您的TenantConnectionStringProvider类:

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: 我并不完全熟悉但我打赌使用Lazy<>可能有益:

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 . 没有经过测试,但是当你真正需要主值时(我假设某个时候以后,在同一个类中使用不同的方法)你可以使用principal.Value然后运行并检索你的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. 如果您可以提供如何获取dbcontext的连接字符串(如何连接),我可以为您提供完整的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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