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

Postman测试API证书认证无证书传入?配置方法与排查

API证书认证配置问题

我是API证书认证(Certificate Authentication)的新手,参考资料编写了API调用时通过TLS握手接受证书的代码。已在Postman的Settings>>Certificates中上传PEM文件,本地测试localhost时断点触发,但未收到传入的证书,请问如何正确配置API的证书认证?


现有代码实现

ServiceCollection扩展类

public static IServiceCollection AddCertificateAuthentication(this IServiceCollection services) {
    services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>{
        options.RevocationMode = X509RevocationMode.NoCheck;
        options.AllowedCertificateTypes = CertificateTypes.All;
        options.Events = new CertificateAuthenticationEvents {
            OnCertificateValidated = context =>{
                var cert = context.ClientCertificate;
                if (cert == null) {
                    return Task.FromResult(AuthenticateResult.Fail("No client certificate provided."));
                }

                // 从证书主题中提取通用名称(CN)
                var cn = cert.Subject.Split(',').FirstOrDefault(part =>part.Trim().StartsWith("CN="))?.Split('=')[1];

                if (string.IsNullOrEmpty(cn)) {
                    return Task.FromResult(AuthenticateResult.Fail("Invalid certificate: CN not found."));
                }

                var claims = new[] {
                    new Claim(ClaimTypes.Name, cn),
                };

                var identity = new ClaimsIdentity(claims, CertificateAuthenticationDefaults.AuthenticationScheme);
                var principal = new ClaimsPrincipal(identity);
                var ticket = new AuthenticationTicket(principal, CertificateAuthenticationDefaults.AuthenticationScheme);

                return Task.FromResult(AuthenticateResult.Success(ticket));
            }
        };
    });

    services.AddAuthorization(options =>{
        options.AddPolicy("RequireCertificate", policy =>{
            policy.AddAuthenticationSchemes(CertificateAuthenticationDefaults.AuthenticationScheme);
            //policy.RequireAuthenticatedUser();
            policy.RequireClaim(ClaimTypes.Role);
        });
    });
    return services;
}

Startup.cs

services.AddCertificateAuthentication();

Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{
    webBuilder.ConfigureKestrel(options =>{
        options.ConfigureHttpsDefaults(httpsOptions =>{
            httpsOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
        });
    });

    webBuilder.UseStartup<Startup>();
}).UseLoggingFramework();
}

Postman配置截图

Postman证书设置截图1
Postman证书设置截图2


问题排查与修复方案

1. 调整Kestrel客户端证书模式

当前ClientCertificateMode.AllowCertificate仅允许客户端提供证书,但不会主动请求证书。需要改为强制要求证书的模式,让Kestrel在TLS握手阶段主动索要客户端证书:

webBuilder.ConfigureKestrel(options =>{
    options.ConfigureHttpsDefaults(httpsOptions =>{
        // 强制要求客户端提供证书,并验证证书链
        httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
        // 如果不需要验证证书链(仅测试场景),可使用:
        // httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificateNoValidation;
    });
});

2. 修正授权策略逻辑

当前授权策略RequireCertificate要求ClaimTypes.Role声明,但证书验证逻辑中仅添加了ClaimTypes.Name,会导致认证通过但授权失败。二选一调整:

  • 方式1:移除角色声明要求
services.AddAuthorization(options =>{
    options.AddPolicy("RequireCertificate", policy =>{
        policy.AddAuthenticationSchemes(CertificateAuthenticationDefaults.AuthenticationScheme);
        policy.RequireAuthenticatedUser();
        // 注释或删除该行
        // policy.RequireClaim(ClaimTypes.Role);
    });
});
  • 方式2:在证书验证时添加角色声明
// 在OnCertificateValidated事件中修改claims数组
var claims = new[] {
    new Claim(ClaimTypes.Name, cn),
    new Claim(ClaimTypes.Role, "ApiClient") // 添加自定义角色声明
};

3. 验证Postman配置

  • 确认上传的PEM文件包含完整的客户端证书(若证书关联私钥,需确保Postman可访问对应私钥文件)
  • 确认请求使用HTTPS协议,且证书配置的域名与localhost匹配(截图中配置无问题)
  • 检查Postman请求设置,确保未禁用客户端证书发送

4. 优化证书验证事件写法

简化异步逻辑,避免不必要的Task.FromResult包装:

options.Events = new CertificateAuthenticationEvents {
    OnCertificateValidated = async context =>{
        var cert = context.ClientCertificate;
        if (cert == null) {
            context.Fail("No client certificate provided.");
            return;
        }

        var cn = cert.Subject.Split(',').FirstOrDefault(part => part.Trim().StartsWith("CN="))?.Split('=')[1];
        if (string.IsNullOrEmpty(cn)) {
            context.Fail("Invalid certificate: CN not found.");
            return;
        }

        var claims = new[] {
            new Claim(ClaimTypes.Name, cn),
            new Claim(ClaimTypes.Role, "ApiClient")
        };

        var identity = new ClaimsIdentity(claims, CertificateAuthenticationDefaults.AuthenticationScheme);
        context.Principal = new ClaimsPrincipal(identity);
        context.Success();
    }
};

5. 确保中间件顺序正确

在Startup.cs的Configure方法中按顺序添加认证、授权中间件:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 其他中间件(如异常处理、静态文件)...

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

    // 路由、端点等中间件...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:53:13