ASP.NET Core 3.1 中的证书认证实现

yog*_*ing 7 c# asp.net asp.net-core-mvc asp.net-core asp.net-core-3.1

我正在 ASP.NET Core 证书身份验证中构建一个小功能,如官方文档中所述

注意:我不是在构建 API,我只是想保护某些控制器的某些 Action 方法,以便仅当客户端具有客户端证书时才打开这些受保护的操作方法。

下图显示我能够保护 现在需要客户端证书的索引操作方法。隐私的其他操作方法不需要客户端证书。结果是 Index action 确实在浏览器中打开(收到 403 错误)但 Privacy action 在浏览器中打开

在此处输入图片说明

完整代码

1.程序.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
        webBuilder.ConfigureKestrel(o =>
        {
            o.ConfigureHttpsDefaults(o =>
                o.ClientCertificateMode =
                    ClientCertificateMode.RequireCertificate);
        });
    });
Run Code Online (Sandbox Code Playgroud)

2.Startup.cs

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddAuthentication(
        CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate(options =>
        {
            options.Events = new CertificateAuthenticationEvents
            {
                OnCertificateValidated = context =>
                {
                    var validationService = context.HttpContext.RequestServices.GetService<MyCertificateValidationService>();

                    if (validationService.ValidateCertificate(context.ClientCertificate))
                    {
                        context.Success();
                    }
                    else
                    {
                        context.Fail("invalid cert");
                    }

                    return Task.CompletedTask;
                },
                OnAuthenticationFailed = context =>
                {
                    context.Fail("invalid cert");
                    return Task.CompletedTask;
                }
            };
        });
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseCertificateForwarding();
    app.UseAuthentication();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}
Run Code Online (Sandbox Code Playgroud)

3. MyCertificateValidationService.cs

public class MyCertificateValidationService
{
    public bool ValidateCertificate(X509Certificate2 clientCertificate)
    {
        var cert = new X509Certificate2(Path.Combine("localhost_root_l1.pfx"), "1234");
        if (clientCertificate.Thumbprint == cert.Thumbprint)
        {
            return true;
        }

        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

4. 安全和不安全的动作方法

[Authorize]
public IActionResult Index()
{
    return View();
}

public IActionResult Privacy()
{
    return View();
}
Run Code Online (Sandbox Code Playgroud)

注意:索引操作方法需要客户端身份验证,而隐私不需要客户端证书。

问题: 我遇到的问题是:

  1. CertificateAuthenticationEvents&OnAuthenticationFailed位于ConfigureServices()我没有调用的 startup.cs 文件的方法上。我通过放置断点来检查它们,但未达到断点。

  2. MyCertificateValidationService.cs 类ValidateCertificate()方法也未调用。我也用断点检查过

请帮助我实施证书授权。

更新

我在 C# 中创建了 2 个证书,如本教程中所述。这些是:

  1. 名为 root_localhost.pfx 的根证书
  2. 名为 client.pfx 的客户端证书

我用这些证书做了两件事:

一种。我将 root_localhost.pfx 添加到本地计算机(使用 CertManager)的受信任根证书颁发机构(在 Windows 上)。

湾 我通过 chrome 浏览器导入了客户端证书。

接下来,我在 VS 2019(控制台)而不是“IIS Express”中选择了项目并运行我的项目。我在隐身窗口中打开网站网址,网址恰好是 - https://localhost:5001

Chrome 要求选择证书,见下图: 在此处输入图片说明

选择它后,我得到无法访问该站点 - ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY,见下图:

在此处输入图片说明

为什么会发生????

小智 1

目前您的应用程序尚未配置为使用客户端证书。原因是您在 IIS Express 中启动(托管)您的应用程序。有2个选择:

1)最简单的一种,切换到以项目模式运行(应用程序将在控制台窗口中运行)。您也可以在控制台中手动运行它。

2) 更复杂一点的方法是配置 IIS Express 以使用客户端证书。按照以下步骤操作: 2.1) 编辑 \config\applicationhost.config 文件并更改以下部分(更改 - 拒绝到允许)。

      <sectionGroup name="security">
        <section name="access" overrideModeDefault="**Allow**" />
        <section name="applicationDependencies" overrideModeDefault="Deny" />
        <sectionGroup name="authentication">
          <section name="anonymousAuthentication" overrideModeDefault="**Allow**" />
Run Code Online (Sandbox Code Playgroud)

2.2)在你的项目中添加以下文件web.config

<configuration>
    <system.webServer>
        <security>
            <access sslFlags="Ssl,SslNegotiateCert,SslRequireCert" />
          <authentication>
            <anonymousAuthentication enabled="true" />
          </authentication>
        </security>
    </system.webServer>
</configuration>
Run Code Online (Sandbox Code Playgroud)

下一个:

客户端身份验证工作的先决条件是拥有客户端证书。您可以使用以下命令或任何其他生成客户端证书的方法来创建自签名证书:

#create key
openssl req -newkey rsa:4096 -keyout key.pem -out csr.pem -nodes -days 365 -subj "/CN=Your name"
#create certificate
openssl x509 -req -in csr.pem -signkey key.pem -out cert.pem -days 365
#self sign it
openssl pkcs12 -export -in cert.pem -inkey key.pem -out your_cert.p12

Run Code Online (Sandbox Code Playgroud)

由于此证书是自签名的,因此您必须将其添加到本地计算机的受信任根证书颁发机构(在 Windows 上)(使用 CertManager)。

之后,您需要使用相同的 CertManager 将其安装(导入)到您的个人证书存储中,但仅限当前用户。替代方法是使用 Chrome 设置(“管理证书”)。Chrome 需要这样做才能将证书发送到服务器。

此外,在您的应用程序中,您可以更改此选项以允许自签名证书。

            services.AddAuthentication(
                    CertificateAuthenticationDefaults.AuthenticationScheme)
                    .AddCertificate(options => 
                    { 
                        **options.AllowedCertificateTypes = CertificateTypes.All**;
Run Code Online (Sandbox Code Playgroud)

完成所有这些更改后,当您访问站点时,它应该要求选择证书。

提示:如果您再次访问同一页面,在关闭所有 Chrome 实例之前,系统可能不会要求您选择要使用的证书。如果您希望它要求选择要使用的证书,请打开一个新的隐身窗口。