如何将应用程序服务注入 AuthenticationHandler

How to inject application service into AuthenticationHandler

我有一个依赖于应用程序服务的自定义 AuthenticationHandler<> 实现。有没有办法从 Simple Injector 解决 AuthenticationHandler 的依赖关系?或者可能是跨线注册,以便可以从 IServiceCollection?

解析应用程序服务

为简单起见,示例实现如下所示:

public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly ITokenDecryptor tokenDecryptor;

    public SecurityTokenAuthHandler(ITokenDecryptor tokenDecryptor,
        IOptionsMonitor<AuthenticationSchemeOptions> options, 
        ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) :
        base(options, logger, encoder, clock) =>
        this.tokenDecryptor = tokenDecryptor;

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync() =>
        return tokenDecryptor.Decrypt(this);
}

...

services.AddAuthentication("Scheme")
    .AddScheme<AuthenticationSchemeOptions, AuthHandler>("Scheme", options => { });

目前的解决方案是手动跨线申请服务,不太方便:

services.AddTransient(provider => container.GetInstance<ITokenDecryptor>());

maybe cross-wire registration so that applications services can be resolved from IServiceCollection?

不,.Net Core不可能自动解析来自Simple Injector的服务。

Cross-wiring is a one-way process. By using AutoCrossWireAspNetComponents, ASP.NET’s configuration system will not automatically resolve its missing dependencies from Simple Injector. When an application component, composed by Simple Injector, needs to be injected into a framework or third-party component, this has to be set up manually by adding a ServiceDescriptor to the IServiceCollection that requests the dependency from Simple Injector. This practice however should be quite rare.

参考:Cross-wiring ASP.NET and third-party services

根据上面的建议,您需要在IServiceCollection中注册服务。您目前已经实现了。

陶老师的回答是对的。实现这一点的最简单方法是 AuthHandler 连接到 Simple Injector。

这可以按如下方式完成:

// Your original configuration:
services.AddAuthentication("Scheme")
    .AddScheme<AuthenticationSchemeOptions, AuthHandler>("Scheme", options => { });

// Cross wire AuthHandler; let Simple Injector create AuthHandler.
// Note: this must be done after the call to AddScheme. Otherwise it will
// be overridden by ASP.NET.
services.AddTransient(c => container.GetInstance<AuthHandler>());

// Register the handler with its dependencies (in your case ITokenDecryptor) with 
// Simple Injector
container.Register<AuthHandler>();
container.Register<ITokenDecryptor, MyAwesomeTokenDecryptor>(Lifestyle.Singleton);

我使用的是 .Net 5,在我从旧的 .net 核心应用程序升级后,Steven 提供的原始版本不再适用于我。我必须:

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddAuthentication("MyScheme")
        .AddScheme<ApiKeyOptions, ApiKeyAuthenticationHandler>("MyScheme", o => { });

    var authHandlerDescriptor = services
        .First(s => s.ImplementationType == typeof(ApiKeyAuthenticationHandler));

    services.Remove(authHandlerDescriptor);

    services.AddTransient(c => container.GetInstance<ApiKeyAuthenticationHandler>());
}