【问题标题】:Simple Injector get current principal in WebAPI using OWINSimple Injector 使用 OWIN 获取 WebAPI 中的当前主体
【发布时间】:2016-05-10 14:26:48
【问题描述】:

在使用 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())
    {
    }

在搞砸了一点之后,我能够做到这一点,但感觉很hacky.. 我添加了一个在身份验证后发生的 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
    }

【问题讨论】:

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


    【解决方案1】:

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

    绝对是您创建它的方式。我对 并不完全熟悉,但我敢打赌,使用Lazy&lt;&gt; 可能会有所帮助:

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

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

    【讨论】:

    • 我不认为 Lazy 在这里会有所帮助,我需要在注射期间立即访问索赔。我将根据正在发生的事情编辑我的帖子。
    • @SSteveadoo 你不应该需要注入构造函数中的声明;这是一种不好的做法,正如 Mark Seemann 解释的那样 here 并且由于主体是运行时数据,所以 this advice 也成立。
    【解决方案2】:

    您可以注册一个Func&lt;ClaimsPrincipal&gt;(工厂)并将其注入您的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>();
    

    【讨论】:

    • 我通过将工厂设置为单例简化了您的注册;因为不需要为每个请求创建一个新的委托。请注意,您永远不应该在注入构造函数中调用工厂,正如我在 Erik 回答的评论中所解释的那样。在您的情况下,它甚至会产生无效的结果,因为在对象图构建期间主体可能不可用。换句话说,虽然工厂旨在延迟对象构造,但您不会延迟任何事情,因为委托是在 ctor 内部调用的。
    • 谢谢@Steven。对于构造函数中工厂的调用,只是举例说明如何获取主体。我会更新我的答案。
    • 赞成。请注意,TenantConnectionStringProvider 也可以成为单例。
    • 我更喜欢 Lazy 类,否则每次使用 Func 都可能得到不同的结果(一般来说)。例如,如果有人决定更改用户,您会得到不同的结果。同样的原因,微软犯了将DateTime.Now 设置为property and not a method 的错误,因为方法通常旨在返回不同的结果,而属性通常是静态的。
    • @ErikPhilips 事实上:是的,Func 是一个坏主意,但通常不是因为它泄漏,而是因为它使消费者的事情变得复杂,而我们应该努力让事情变得更简单消费者。
    猜你喜欢
    • 2015-03-29
    • 2014-12-26
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多