简单注入器使用 OWIN 在 WebAPI 中获取当前主体

本文关键字:获取 主体 WebAPI 注入器 OWIN 简单 | 更新日期: 2023-09-27 18:32:46

是否可以使用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
    }

简单注入器使用 OWIN 在 WebAPI 中获取当前主体

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

是否意味着这是不可能的,因为此步骤是在创建控制器之前完成的?

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

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

未经测试,但是当您实际需要主体值时(我假设稍后,在同一类中的不同方法中(,您可以使用principal.Value然后它会运行并检索您的ClaimsPrincipal。 当然,这些都是巨大的假设,因为没有代码来查看所有内容是如何连接的。 如果您可以提供如何获取数据库上下文的连接字符串(如何连接(,我可能会为您提供一个完整的解决方案。