You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自托管Asp Net Core Web服务器客户端证书认证失效问题排查

问题描述

我在测试自托管ASP.NET Core Web服务器(Kestrel)时,使用自签名证书实现客户端认证遇到异常:自定义证书验证类的ValidateCertificate()返回false(即证书验证失败),但客户端访问控制器路由时,控制器方法仍会被执行。

相关日志片段:

...
AspNetCore.Routing.EndpointRoutingMiddleware : Request matched endpoint ‘GetMyData…‘
AspNetCore.Authentication.Certificate.CertificateAuthenticationHandler : Certificate was not authenticated. Failure message: invalid cert
AspNetCore.Routing.EndpointMiddleware : Executing endpoint ‘GetMyData…‘
...

启动代码如下:

WebApplicationBuilder webBuilder = WebApplication.CreateBuilder();
var webHostBuilder = builder.WebHost;

X509Certificate2 rootCert = new X509Certificate2(hostCertFilePath, hostCertPassword);

webHostBuilder.ConfigureKestrel(o =>
{
    o.ConfigureHttpsDefaults(o =>
    {
        o.ServerCertificate = rootCert;
        o.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
    });
});

webHostBuilder.UseKestrel(o =>
{
    o.Listen(IPAddress.Parse(myHttpsEndPointIpAddr), myHttpsEndPointPort,
        listenOptions =>
        {
            listenOptions.UseHttps();
        });
    o.Listen(IPAddress.Parse(myHttpEndPointIpAddr), myHttpEndPointPort);
});

var services = webBuilder.Services;

services.AddTransient<MyCustomCertificateValidationService>();
services
    .AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
    .AddCertificate(options =>
    {
        options.AllowedCertificateTypes = CertificateTypes.SelfSigned;
        options.Events = new CertificateAuthenticationEvents
        {
            OnCertificateValidated = context =>
            {
                var validationService = context.HttpContext.RequestServices
                    .GetService<MyCustomCertificateValidationService>();

                if (validationService.ValidateCertificate(context.ClientCertificate))
                {
                    context.Success();
                }
                else
                {
                    context.Fail("invalid cert");
                }

                return Task.CompletedTask;
            },
            OnAuthenticationFailed = context =>
            {
                context.Fail("invalid cert");
                return Task.CompletedTask;
            }
        };
    });

...

var app = webBuilder.Build();

app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

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

自定义证书验证类:

public class MyCustomCertificateValidationService
{
    public bool ValidateCertificate(X509Certificate2 clientCertificate)
    {
        // todo: check certificate thumbnail
        return false;
    }
}
原因及解决方法

核心问题是缺少授权规则限制:UseAuthentication()仅完成认证逻辑(标记请求是否通过证书验证),但UseAuthorization()需要明确的规则才能拦截未通过认证的请求。默认情况下,如果没有配置任何授权策略,所有请求都会被放行,哪怕认证失败。

修复方案二选一:

1. 全局配置默认授权策略

在服务配置中添加全局 fallback 策略,要求所有请求必须通过认证:

services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

该策略会作用于所有未单独设置授权规则的控制器和路由,直接拒绝未认证的请求。

2. 给目标控制器/Action添加授权特性

如果不需要全局生效,可在特定控制器或Action上标注[Authorize]特性,指定使用证书认证方案:

[Authorize(AuthenticationSchemes = CertificateAuthenticationDefaults.AuthenticationScheme)]
public class MyDataController : ControllerBase
{
    [HttpGet("GetMyData")]
    public IActionResult GetMyData()
    {
        // 控制器逻辑
    }
}

原理补充

  • UseAuthentication():执行证书验证,认证失败时会将HttpContext.User标记为未认证状态,但不会主动终止请求。
  • UseAuthorization():根据配置的授权规则检查用户认证状态,若无规则则默认允许所有请求,这就是验证失败但控制器仍执行的原因。

内容的提问来源于stack exchange,提问作者RickyTad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 15:55:33