Служба проверки сертификатов, возвращаемая HttpContext.RequestServices.GetService() равно нулю

#c# #asp.net-core

Вопрос:

Я пытаюсь следить за документацией Microsoft и другими блогами, в которых демонстрируется проверка подлинности сертификата в ASP.NET Ядро. Службы запросов на вызов.GetService() возвращает значение null. Я добавил нулевую проверку переменной validationService для проверки на вменяемость, что это была нулевая ссылка.

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>
        {
            options.RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck;
            options.Events = new CertificateAuthenticationEvents
            {
                OnCertificateValidated = context =>
                {
                    var validationService = context.HttpContext.RequestServices.GetService<MyCertificateValidationService>();

                    if (validationService == null)
                    {
                        throw new NullReferenceException("Validation Service returned by GetService<MyCertificateValidationService>() is null");
                    }

                    if (validationService.ValidateCertificate(context?.ClientCertificate))
                    {
                        var claims = new[]
                    {
                        new Claim(
                            ClaimTypes.NameIdentifier,
                            context.ClientCertificate.Subject,
                            ClaimValueTypes.String,
                            context.Options.ClaimsIssuer),
                        new Claim(
                            ClaimTypes.Name,
                            context.ClientCertificate.Subject,
                            ClaimValueTypes.String,
                            context.Options.ClaimsIssuer)
                    };

                        context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
                        context.Success();
                    }

                    return Task.CompletedTask;
                }
            };
        });

        services.AddControllers();

        services.AddMvc()
            .AddXmlSerializerFormatters();
    }
 

Класс службы проверки:

 public class MyCertificateValidationService
{
    public bool ValidateCertificate(X509Certificate2 clientCertificate)
    {
        bool valid = false;

        var cert = new X509Certificate2(Path.Combine("Test.crt"), ")F@4R9df3s75(5g0");

        if (clientCertificate.Thumbprint == cert.Thumbprint)
        {
            valid = true;
        }

        return valid;
    }
}
 

Вот метод настройки при запуске:

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseCertificateForwarding();
        app.UseAuthentication();

        loggerFactory.AddSerilog();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/error");
        }

        app.UseMiddleware<SerilogMiddleware>();

        app.UseMiddleware<AuthenticationMiddleware>();
        
        app.UseRouting();

        app.UseEndpoints(endPoints =>
        {
            endPoints.MapControllers();
        });
    }
 

Комментарии:

1. где вы регистрируете свой MyCertificateValidationService ?

2. Возможно, в этом и заключается проблема. Где *я должен это сделать? Как мне это сделать? Либо в документации, которой я следую, это не подробно описано, либо я полностью пропустил это.

3. вы можете зарегистрировать его внутри Startup.ConfigureServices вот так services.AddSingleton<MyCertificateValidationService>() — поскольку ваш сервис выглядит как без состояния и может быть потокобезопасным, мы можем зарегистрировать его как одноэлементный.

4. Большое вам спасибо за совет.

Ответ №1:

Как говорит кинг кинг, если вы хотите использовать службу обработки пользовательских сертификатов, вам следует сначала зарегистрировать ее, а затем использовать, как показано ниже:

Обратите внимание: В документе упоминается , что вы также можете использовать ICertificateValidationService , вам также необходимо самостоятельно создать эту службу и зарегистрировать ее как службу, если вы хотите получить ее из context.HttpContext.RequestServices.GetService метода.

 public void ConfigureServices(IServiceCollection services)
    {
         services.AddSingleton<MyCertificateValidationService>();
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>
                {
                    options.RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck;
                    options.Events = new CertificateAuthenticationEvents
                    {
                        OnCertificateValidated = context =>
                        {
                            var validationService = context.HttpContext.RequestServices.GetService<MyCertificateValidationService>();
        
                            if (validationService == null)
                            {
                                throw new NullReferenceException("Validation Service returned by GetService<MyCertificateValidationService>() is null");
                            }
        
                            if (validationService.ValidateCertificate(context?.ClientCertificate))
                            {
                                var claims = new[]
                            {
                                new Claim(
                                    ClaimTypes.NameIdentifier,
                                    context.ClientCertificate.Subject,
                                    ClaimValueTypes.String,
                                    context.Options.ClaimsIssuer),
                                new Claim(
                                    ClaimTypes.Name,
                                    context.ClientCertificate.Subject,
                                    ClaimValueTypes.String,
                                    context.Options.ClaimsIssuer)
                            };
        
                                context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
                                context.Success();
                            }
        
                            return Task.CompletedTask;
                        }
                    };
                });
        
                services.AddControllers();
        
                services.AddMvc()
                    .AddXmlSerializerFormatters();
            }
 

Также я предлагаю вам ознакомиться с этой демонстрацией на github, чтобы узнать, как она работает с аутентификацией сертификата клиента.