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

如何在Angular 13与ASP.NET Core 6 Web API间建立HTTPS客户端证书认证连接?

Angular 发送客户端证书到 ASP.NET Core 6 API 解决方案

针对你遇到的 ERR_BAD_SSL_CLIENT_AUTH_CERT 错误,核心问题在于浏览器对客户端证书的安全限制、Angular请求配置与后端CORS/认证逻辑的配合,以下是具体解决步骤:


1. 确保客户端证书正确安装到浏览器/系统存储

浏览器无法直接读取本地文件中的证书,必须将包含私钥的客户端证书(连同中间证书链)安装到对应位置:

  • Windows系统:打开certmgr.msc,将证书导入到当前用户→个人→证书存储
  • Chrome/Firefox:通过浏览器设置的证书管理入口,将证书导入到"个人"类别
  • 关键验证:证书的「增强型密钥使用」扩展必须包含客户端身份验证(OID: 1.3.6.1.5.5.7.3.2),且私钥可正常使用

2. Angular 请求配置:触发证书发送

Angular本身无法直接操作证书,需通过浏览器的TLS握手完成发送,因此请求必须开启凭据支持:

import { HttpClient } from '@angular/common/http';

@Component({/* 组件配置 */})
export class YourComponent {
  constructor(private http: HttpClient) {}

  callSecureApi() {
    const apiUrl = 'https://localhost:7120/api/your-endpoint';
    return this.http.get(apiUrl, {
      withCredentials: true // 告知浏览器携带凭证(包含客户端证书相关信息)
    });
  }
}

3. 完善 ASP.NET Core 的 CORS 配置

允许跨域凭据是浏览器发送客户端证书的前提,且CORS规则不能使用通配符*作为Origin:

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAngularApp", policy =>
    {
        policy.WithOrigins("http://localhost:4200") // 替换为你的Angular应用实际地址
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials(); // 必须开启,否则浏览器会拦截证书发送
    });
});

// 中间件顺序注意:UseCors需放在UseRouting之后、UseAuthorization之前
app.UseRouting();
app.UseCors("AllowAngularApp");
app.UseAuthentication();
app.UseAuthorization();

4. 调整 Kestrel 客户端证书模式(可选优化)

你当前使用的ClientCertificateMode.RequireCertificate会在TLS握手阶段强制要求证书,跨域场景下部分浏览器可能不会自动触发证书选择。可改为延迟验证模式,将证书验证移到授权逻辑中:

修改Kestrel配置

builder.WebHost.ConfigureKestrel(options =>
{
    options.ConfigureHttpsDefaults(listenOptions =>
    {
        listenOptions.ServerCertificate = serverCertificate;
        listenOptions.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
        listenOptions.ClientCertificateMode = ClientCertificateMode.DelayCertificate; // 改为延迟验证
        listenOptions.CheckCertificateRevocation = false;
        listenOptions.ClientCertificateValidation = (certificate, chain, errors) =>
        {
            return chain.Build(certificate); // 保留原有验证逻辑
        };
    });
    options.ListenLocalhost(7120, op =>
    {
        op.UseHttps(serverCertificate);
        op.Protocols = HttpProtocols.Http1AndHttp2;
        op.UseConnectionLogging();
    });
});

添加证书认证服务

builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
    .AddCertificate(options =>
    {
        options.AllowedCertificateTypes = CertificateTypes.Chained;
        options.Events = new CertificateAuthenticationEvents
        {
            OnCertificateValidated = context =>
            {
                if (context.Chain.Build(context.ClientCertificate))
                {
                    // 可在此添加用户身份映射逻辑,比如生成ClaimsPrincipal
                    context.Success();
                }
                else
                {
                    context.Fail("证书链验证失败");
                }
                return Task.CompletedTask;
            }
        };
    });

// 启用认证中间件
app.UseAuthentication();
app.UseAuthorization();

控制器添加授权标记

[Authorize(AuthenticationSchemes = CertificateAuthenticationDefaults.AuthenticationScheme)]
[ApiController]
[Route("api/[controller]")]
public class YourController : ControllerBase
{
    // 接口逻辑
}

5. 浏览器端排查

  • 如果浏览器未弹出证书选择框:检查服务器根CA是否已被浏览器信任,或证书的EKU扩展是否包含客户端身份验证
  • 查看SSL日志:Chrome可通过chrome://net-internals/#ssl查看TLS握手过程中的具体错误信息

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 11:25:43