.NET Core 5/6 API证书认证经代理时出现403禁止访问问题
解决方案:代理转发下的ASP.NET Core证书认证403问题
问题根源
当请求经过代理转发时,核心问题有两个:
- 代理未正确将客户端证书传递至后端应用;
- ASP.NET Core默认不信任代理转发的请求头,无法识别真实客户端信息或传递的证书,导致认证失败返回403。
步骤1:配置ASP.NET Core信任代理
在ConfigureServices中添加转发头配置,让应用信任代理的转发信息:
public void ConfigureServices(IServiceCollection services) { // 配置转发头,信任指定代理 services.Configure<ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; // 将你的代理服务器IP加入信任列表,防止伪造转发头 options.KnownProxies.Add(IPAddress.Parse("你的代理IP")); }); // 原有的证书认证配置 services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme) .AddCertificate() .AddCertificateCache(); // 其他服务配置 }
在Configure中,必须将UseForwardedHeaders()放在UseAuthentication()之前:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseForwardedHeaders(); // 这行需前置,确保认证逻辑能获取正确的客户端信息 app.UseAuthentication(); // 其他应用中间件配置 }
步骤2:确保代理服务器正确传递客户端证书
根据代理类型调整配置:
- Nginx:开启请求头传递,并将客户端证书转为Base64通过自定义头转发:
location / { proxy_pass http://你的后端应用地址; proxy_pass_request_headers on; # 转发客户端证书至后端 proxy_set_header X-Client-Certificate $ssl_client_cert; } - IIS:在代理站点的SSL设置中开启「要求SSL」和「协商客户端证书」,同时确保后端应用池拥有读取客户端证书的权限。
步骤3:调整证书认证逻辑适配代理场景
如果代理通过请求头传递证书信息(如上述的X-Client-Certificate),修改认证配置从请求头读取并验证证书:
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme) .AddCertificate(options => { options.AllowedCertificateTypes = CertificateTypes.All; options.Events = new CertificateAuthenticationEvents { OnCertificateValidated = context => { // 从代理传递的请求头获取证书 var certHeader = context.Request.Headers["X-Client-Certificate"].FirstOrDefault(); if (!string.IsNullOrEmpty(certHeader)) { // 清理证书格式(移除首尾标识) var cleanCert = certHeader.Replace("-----BEGIN CERTIFICATE-----", "") .Replace("-----END CERTIFICATE-----", "") .Trim(); var certBytes = Convert.FromBase64String(cleanCert); var clientCert = new X509Certificate2(certBytes); // 自定义验证逻辑(示例:使用证书主题作为身份标识) context.Principal = new ClaimsPrincipal( new ClaimsIdentity( new[] { new Claim(ClaimTypes.Name, clientCert.Subject) }, CertificateAuthenticationDefaults.AuthenticationScheme ) ); context.Success(); } return Task.CompletedTask; } }; }) .AddCertificateCache();
步骤4:排查验证
添加临时中间件打印请求信息,确认证书和转发头是否正确传递:
app.Use(async (context, next) => { var clientCert = context.Connection.ClientCertificate; var forwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); var certHeader = context.Request.Headers["X-Client-Certificate"].FirstOrDefault(); // 输出至日志或控制台用于排查 Console.WriteLine($"客户端证书主题: {clientCert?.Subject ?? "未获取到证书"}"); Console.WriteLine($"转发客户端IP: {forwardedFor ?? "未获取到转发IP"}"); Console.WriteLine($"代理传递的证书头: {certHeader ?? "未传递证书头"}"); await next(); });
内容的提问来源于stack exchange,提问作者NoviceDeveloper
相关产品推荐
相关产品推荐

