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

.NET Core 3.1 Web API如何实现Azure AD Token与客户端证书双认证

没问题,在.NET Core 3.1里完全可以实现这种双认证共存的模式,不用拆分现有Web应用,我给你梳理下具体的实现步骤和代码示例:

核心思路

我们要在同一个API里同时注册两种认证方案:

  1. 保留你现有的Azure AD JWT Token认证(AddProtectedWebApi)
  2. 添加客户端证书认证方案
    然后通过自定义授权策略,允许用户通过任意一种认证方式访问API。

具体实现步骤

1. 配置两种认证方案

在Startup.cs的ConfigureServices方法里,先保留你原有的Azure AD配置,再添加证书认证的配置:

public void ConfigureServices(IServiceCollection services)
{
    // 1. 保留现有Azure AD JWT认证配置
    services.AddProtectedWebApi(options =>
    {
        // 你的原有配置,比如租户ID、API客户端ID等
        options.TenantId = "your-tenant-id";
        options.ClientId = "your-api-client-id";
        // 其他Azure AD相关配置...
    });

    // 2. 添加客户端证书认证
    services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate(options =>
        {
            options.AllowedCertificateTypes = CertificateTypes.All;
            // 自定义证书验证逻辑
            options.Events = new CertificateAuthenticationEvents
            {
                OnCertificateValidated = context =>
                {
                    var clientCert = context.ClientCertificate;
                    
                    // 这里可以根据你的需求添加验证规则:比如检查颁发者、有效期、证书主题等
                    if (clientCert.Issuer.Equals("your-trusted-issuer", StringComparison.OrdinalIgnoreCase)
                        && clientCert.NotAfter >= DateTime.UtcNow)
                    {
                        // 将证书信息转换为标准ClaimsPrincipal,和JWT认证的用户格式统一
                        var claims = new[]
                        {
                            new Claim(ClaimTypes.NameIdentifier, clientCert.SubjectName.Name),
                            new Claim(ClaimTypes.Name, clientCert.SubjectName.Name),
                            // 可自定义添加角色或其他声明
                            new Claim(ClaimTypes.Role, "Cert-Authenticated-User")
                        };
                        context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
                        context.Success();
                    }
                    else
                    {
                        context.Fail("Invalid client certificate");
                    }
                    return Task.CompletedTask;
                }
            };
        });

    // 3. 配置默认授权策略:允许两种认证方案任一通过
    services.AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder(
            JwtBearerDefaults.AuthenticationScheme,
            CertificateAuthenticationDefaults.AuthenticationScheme)
            .RequireAuthenticatedUser()
            .Build();

        // 可选:给特定接口配置专属策略(比如某些接口只允许证书认证)
        options.AddPolicy("OnlyCertificate", policy =>
            policy.RequireAuthenticatedUser()
                  .AddAuthenticationSchemes(CertificateAuthenticationDefaults.AuthenticationScheme));
    });

    // 其他服务配置...
    services.AddControllers();
}

2. 调整中间件顺序和Kestrel配置

在Configure方法里确保认证、授权中间件的顺序正确,同时配置Kestrel接受可选的客户端证书(因为3.1没有5.0的Optional证书功能,我们用AllowCertificate让Kestrel接受但不强制要求证书):

2.1 Startup.cs的Configure方法

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseHttpsRedirection();
    app.UseRouting();

    // 必须先添加认证中间件,再添加授权中间件
    app.UseAuthentication();
    app.UseAuthorization();

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

2.2 配置Kestrel接受可选证书

可以在appsettings.json里添加配置:

"Kestrel": {
  "Endpoints": {
    "Https": {
      "Url": "https://localhost:5001",
      "SslProtocols": "Tls12",
      "ClientCertificateMode": "AllowCertificate"
    }
  }
}

或者在Program.cs里代码配置:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                options.ListenAnyIP(5001, listenOptions =>
                {
                    listenOptions.UseHttps(httpsOptions =>
                    {
                        httpsOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
                    });
                });
            });
            webBuilder.UseStartup<Startup>();
        });

效果说明

配置完成后,你的API就能同时支持两种认证方式:

  • 当前端在请求头里携带Authorization: Bearer {JWT-Token}时,会自动走Azure AD的JWT认证流程
  • 当前端携带客户端证书发起请求时,会触发证书认证逻辑,验证通过后即可访问API
  • 如果你给某些接口标记了[Authorize(Policy = "OnlyCertificate")],则该接口仅接受证书认证的请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 07:37:37