自托管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
相关产品推荐
相关产品推荐

