【问题标题】:How to inject ClaimsPrincipal in Nancy如何在 Nancy 中注入 ClaimsPrincipal
【发布时间】:2017-12-08 05:31:44
【问题描述】:

我有一个 Nancy 模块和一个装饰器类,它们需要知道 ClaimsPrincipal 才能检索用户的电子邮件地址。所以我将构造函数声明为

public EmailDecorator(IDbConnectionFactory connectionFactory,
                      IPrincipal principal,
                      IEmailClient emailClient) : base(connectionFactory)

我正在努力弄清楚如何将主体注入构造函数。我正在为 DI 使用 Simple Injector,它非常有效。但是,如果我覆盖 ConfigureRequestContainer() 方法,它作为 NancyContext 的参数,实例化 IPrincipal 我得到一个异常

protected override void ConfigureRequestContainer(
    TinyIoCContainer container, NancyContext context)
{
    container.Register<IPrincipal>((c, o) => context.CurrentUser); 
    base.ConfigureRequestContainer(container, context);
}

异常表明 Simple Injector 不知道在默认 TinyIOC 容器中注册的IPrincipal

配置无效。创建 InvoiceModule 类型的实例失败。 EmailDecorator 类型的构造函数包含名为“principal”的参数和未注册的 IPrincipal 类型。请确保 IPrincipal 已注册,或更改 EmailDecorator 的构造函数。

编辑

我花了太长时间试图解决这个问题,我怀疑答案是停止尝试这样做。在我原来的例子中,我试图将 IPrincipal 注入到不正确的装饰器构造函数中。相反,我需要注入某种形式的服务,允许我在调用装饰器中的方法之一时派生 IPrincipal,例如Func&lt;IPrincipal&gt;。 Nancy 提供了一个可覆盖的方法 ConfigureRequestContainer(),每个请求都会调用它,因此可能会被使用:

protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
    container.Register<Func<IPrincipal>>((c, o) =>
    {
        return () => context.CurrentUser;
    });
}

除了请求容器是 TinyIoCContainer 并且我使用的是 SimpleInjector。那么,也许我可以添加一个 SimpleInjector 注册,将解析卸载到请求容器?

_container.RegisterSingleton<Func<IPrincipal>>(() => nancy.Resolve<Func<IPrincipal>>());

其实不是,nancy 和请求容器不是同一个容器。所以也许某处有一个容器可以成功解析 IPrincipal 但我不知道如何访问它。练习的目的是避免修改 repo 代码的方法签名以包含 ClaimsPrincipal,这有点像过去可以调用 Thread.CurrentPrincipal。仍在寻找线索,但将开始修改方法签名以包含 ClaimsPrincipal。

【问题讨论】:

  • 我对 Nancy 的经验太少,无法立即回答您的问题,但如果您可以链接到 Github 上我可以在本地运行的最小工作示例,我可以为您解决这个问题。跨度>
  • 我不知道 Simple Injector 的事情,但您的代码使用 Tiny IoC 作为请求容器。也许您在错误的容器中注册了委托人。我也不确定 ClaimsPrincipal 是否足够早地解决,让您注册它。查看此讨论,它基于 Nancy 1.x(IUserIdentity 而不是 Principal),但应该是相关的:github.com/NancyFx/Nancy/issues/1453
  • 是的,我发现自己在兜圈子。 ConfigureRequestContainer 中的 NancyContext 包含 ClaimsPrincipal 但我无法从 SIMple Injector 访问请求容器。

标签: c# nancy simple-injector


【解决方案1】:

答案是使用IHttpContextAccessor。在 Startup.cs 的 ConfigureServices() 方法中添加一个新的服务定义:

public void ConfigureServices(IServiceCollection services)
{           
    services.AddSingleton<IAppSettings>(settings);
    services.AddSingleton<IHttpContextAccessor>(new HttpContextAccessor());
    …
 }

然后将app.ApplicationServices作为参数传递给引导程序:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAppSettings settings)
{
    var log = ConfigureLogger(settings);
    app.UseOwin(buildFunc => 
    { 
        buildFunc.UseMonitoringAndLogging(log, HealthCheckAsync);
        buildFunc.UseNancy(cfg => 
            cfg.Bootstrapper = new Bootstrapper(env, log, app.ApplicationServices));
    });
}

在Bootstrapper类ApplicationStartup()方法中,在Simple Injector容器中注册服务:

    public Bootstrapper(IHostingEnvironment env, ILogger log, IServiceProvider services)
    {
        _env = env;
        _log = log;
        _services = services;
    }

    …

    _container.Register<IHttpContextAccessor>(() =>
        (IHttpContextAccessor) _services.GetService(typeof(IHttpContextAccessor))); 

然后在装饰器类中,将IHttpContextAccessor添加到构造函数中:

public EmailDecorator(IDbConnectionFactory connectionFactory,
                      ILogger log,
                      IHttpContextAccessor httpContextAccessor,
                      IEmailClient emailClient) : base(connectionFactory, log)
{
    _emailClient = emailClient;
    _httpContextAccessor = httpContextAccessor;
}

ClaimsPrincipal 可以通过 _httpContextAccessor.HttpContext 属性访问。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多