.net core 3.0 证书认证

.net core 3.0 Certificate authentication

最近我将 API 从 .net core 2.2 迁移到 .net core 3.0,以便使用证书实施身份验证。

我已按照此 Microsoft 文档:https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-3.0 来完成我的工作。但我面临一个问题: 当我调用用 [Authorize] 属性修饰的控制器方法时,从不执行证书验证。如果请求的 header 中没有证书,我会得到一个 403,这是必需的行为,但是如果我放置证书,则假定的行为应该是通过指纹验证,但什么都没有...

这是我的证书验证服务:

public class CertificateValidationService
{
    public bool ValidateCertificate(X509Certificate2 clientCertificate, string thumbprintToChek) =>
        clientCertificate.Thumbprint.Equals(thumbprintToChek);
}

如文档中所述,在 StartUp.cs 中,我在 ConfigureServices 方法

中设置了以下代码行
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
            .AddCertificate(options => // code from ASP.NET Core sample
            {
                options.AllowedCertificateTypes = CertificateTypes.All;
                options.Events = new CertificateAuthenticationEvents
                {
                    OnCertificateValidated = context =>
                    {
                        var validationService = context.HttpContext.RequestServices.GetService<CertificateValidationService>();

                        if (validationService.ValidateCertificate(context.ClientCertificate, Configuration.GetValue<string>("Apim:CertificateThumbprint")))
                        {
                            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();
                        }
                        else
                        {
                            context.Fail("Invalid certificate.");
                        }

                        return Task.CompletedTask;
                    }
                };

                options.Events = new CertificateAuthenticationEvents
                {
                    OnAuthenticationFailed = context =>
                    {
                        context.Fail("Certificate not valid.");

                        return Task.CompletedTask;
                    }

                };
            });

        services.AddCertificateForwarding(options =>
        {
            options.CertificateHeader = "X-ARR-ClientCert";
            options.HeaderConverter = (headerValue) =>
            {
                X509Certificate2 clientCertificate = null;
                if (!string.IsNullOrWhiteSpace(headerValue))
                {
                    byte[] bytes = headerValue.ToByteArray();
                    clientCertificate = new X509Certificate2(bytes);
                }
                return clientCertificate;
            };
        });

我还使用以下代码填充了 Configure 方法:

app.UseCertificateForwarding();
app.UseAuthentication();

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

所以当我向 API 发出请求时,CertificateForwarding 委托被称为很好,但身份验证委托,从来没有。

但是,我已经尝试在一个全新的项目(仅用于测试)中实现此身份验证,它运行良好。

您对 options.Events 的分配已完成两次。这样 OnCertificateValidated 的默认实现会覆盖您的事件处理程序,并且您的 CertificateValidationService 将永远不会被调用。

组合这两个事件处理程序应该会得到预期的结果:

options.Events = new CertificateAuthenticationEvents
{
    OnCertificateValidated = context =>
    {
        // Your implementation here.
    },
    OnAuthenticationFailed = context =>
    {
        // Your implementation here.
    }
};