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

时间:2016-02-01 23:23:15

标签: c# asp.net asp.net-web-api owin simple-injector

无论如何都要访问当前主体并且在请求使用Simple Injector到达控制器之前?我正在使用OWIN和Asp.net身份。

我有一个DbContext,我注入到我的控制器中,但是这个上下文将根据经过身份验证的用户获得它的连接字符串。这是我到目前为止所做的,

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

然后在我的TenantConnectionStringProvider中,我有了这个,

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

但校长没有索赔。我意识到声明仅在控制器创建后才可用。这是否意味着它是不可能的,因为这一步是在创建控制器之前进行的?

编辑: 这基本上是代码的其余部分:

WebApi控制器

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

租户上下文(仅从EF继承自DbContext):

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

稍微乱了一下后,我能够做到这一点,但感觉非常黑客...... 我添加了一个在身份验证后发生的OWIN中间件。我不知道为什么,但我在这里有所有经过身份验证的用户信息,但是当它转到TenantConnectionStringProvider时,HttpRequestMessage上没有这些信息。

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

然后在我的TenantConnectionStringProvider中,我就这样做了,

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

2 个答案:

答案 0 :(得分:5)

您可以注册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();
    }
}

注册应该是这样的(不确定......):

// 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>();

答案 1 :(得分:3)

  

这是否意味着它是不可能的,因为这一步是在创建控制器之前进行的?

绝对是你创造它的方式。我并不完全熟悉,但我打赌使用Lazy<>可能会有所帮助:

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

未经过测试,但是当实际上需要主值(我假设某个时候以后,在同一个类中采用不同的方法)时,您可以使用principal.Value并且然后会运行并检索您的ClaimsPrincipal。这些是巨大的假设,因为没有代码可以看到一切都是如何连线的。如果您可以提供如何获取dbcontext的连接字符串(如何连接),我可以为您提供完整的解决方案。