靠近我 發表於 2022-9-23 00:01:00

.NET 部署 多域名 Https(SSL)通过代码方式

<p>  在上一个文章中,传送门,给大家介绍了怎么在配置文件中使用&nbsp;Kestrel 部署 Https,正好今天有小伙伴稳问到:可以通过代码的方式实现&nbsp;Kestrel 的 Https 的部署吗?答案是肯定的,我们这次一样去不是多个域名。</p>
<p>  在使用代码实现中,我是主要使用到 ListenOptions.UseHttps,我们先看看官方文档怎么说吧,不想看我的可以直接跳转到官方文档,传送门</p>
<hr>
<p>&nbsp;</p>
<p id="listenoptionsusehttps-1" class="heading-anchor"><strong><span style="font-size: 18px">ListenOptions.UseHttps</span></strong></p>
<p>将 Kestrel 配置为使用 HTTPS。</p>
<p><code>ListenOptions.UseHttps</code>&nbsp;扩展:</p>
<ul>
<li><code>UseHttps</code>:将 Kestrel 配置为使用 HTTPS,采用默认证书。 如果没有配置默认证书,则会引发异常。</li>
<li><code>UseHttps(string fileName)</code></li>
<li><code>UseHttps(string fileName, string password)</code></li>
<li><code>UseHttps(string fileName, string password, Action&lt;HttpsConnectionAdapterOptions&gt; configureOptions)</code></li>
<li><code>UseHttps(StoreName storeName, string subject)</code></li>
<li><code>UseHttps(StoreName storeName, string subject, bool allowInvalid)</code></li>
<li><code>UseHttps(StoreName storeName, string subject, bool allowInvalid, StoreLocation location)</code></li>
<li><code>UseHttps(StoreName storeName, string subject, bool allowInvalid, StoreLocation location, Action&lt;HttpsConnectionAdapterOptions&gt; configureOptions)</code></li>
<li><code>UseHttps(X509Certificate2 serverCertificate)</code></li>
<li><code>UseHttps(X509Certificate2 serverCertificate, Action&lt;HttpsConnectionAdapterOptions&gt; configureOptions)</code></li>
<li><code>UseHttps(Action&lt;HttpsConnectionAdapterOptions&gt; configureOptions)</code></li>
</ul>
<p><code>ListenOptions.UseHttps</code>&nbsp;参数:</p>
<ul>
<li><code>filename</code>&nbsp;是证书文件的路径和文件名,关联包含应用内容文件的目录。</li>
<li><code>password</code>&nbsp;是访问 X.509 证书数据所需的密码。</li>
<li><code>configureOptions</code>&nbsp;是配置&nbsp;<code>HttpsConnectionAdapterOptions</code>&nbsp;的&nbsp;<code>Action</code>。 返回&nbsp;<code>ListenOptions</code>。</li>
<li><code>storeName</code>&nbsp;是从中加载证书的证书存储。</li>
<li><code>subject</code>&nbsp;是证书的主题名称。</li>
<li><code>allowInvalid</code>&nbsp;指示是否存在需要留意的无效证书,例如自签名证书。</li>
<li><code>location</code>&nbsp;是从中加载证书的存储位置。</li>
<li><code>serverCertificate</code>&nbsp;是 X.509 证书。</li>
</ul>
<p>在生产中,必须显式配置 HTTPS。 至少必须提供默认证书。</p>
<p>下面要描述的支持的配置:</p>
<ul>
<li>无配置</li>
<li>从配置中替换默认证书</li>
<li>更改代码中的默认值</li>
</ul>
<p id="no-configuration-1" class="heading-anchor"><strong><span style="font-size: 18px">无配置</span></strong></p>
<p>Kestrel 在&nbsp;<code>http://localhost:5000</code>&nbsp;和&nbsp;<code>https://localhost:5001</code>&nbsp;上进行侦听(如果默认证书可用)。</p>
<p id="replace-the-default-certificate-from-configuration-1" class="heading-anchor"><strong><span style="font-size: 18px">从配置中替换默认证书</span></strong></p>
<p>Kestrel 可以使用默认 HTTPS 应用设置配置架构。 从磁盘上的文件或从证书存储中配置多个终结点,包括要使用的 URL 和证书。</p>
<p>架构的注意事项:</p>
<ul>
<li>终结点的名称不区分大小写。 例如,由于再也无法解析标识符“Families”,因此&nbsp;<code>HTTPS</code>&nbsp;and&nbsp;<code>Https</code>&nbsp;是等效的。</li>
<li>每个终结点都要具备&nbsp;<code>Url</code>&nbsp;参数。 此参数的格式和顶层&nbsp;<code>Urls</code>&nbsp;配置参数一样,只不过它只能有单个值。</li>
<li>这些终结点不会添加进顶层&nbsp;<code>Urls</code>&nbsp;配置中定义的终结点,而是替换它们。 通过&nbsp;<code>Listen</code>&nbsp;在代码中定义的终结点与在配置节中定义的终结点相累积。</li>
<li><code>Certificate</code>&nbsp;部分是可选的。 如果未指定&nbsp;<code>Certificate</code>&nbsp;部分,则使用&nbsp;<code>Certificates:Default</code>&nbsp;中定义的默认值。 如果没有可用的默认值,则使用开发证书。 如果没有默认值,且开发证书不存在,则服务器将引发异常,并且无法启动。</li>
<li><code>Certificate</code>&nbsp;部分支持多个证书源。</li>
<li>只要不会导致端口冲突,就能在配置中定义任何数量的终结点。</li>
</ul>
<p id="certificate-sources-1" class="heading-anchor"><strong><span style="font-size: 16px">证书源</span></strong></p>
<p>可以将证书节点配置为从多个源加载证书:</p>
<ul>
<li><code>Path</code>&nbsp;和&nbsp;<code>Password</code>&nbsp;用于加载 .pfx 文件。</li>
<li><code>Path</code>、<code>KeyPath</code>&nbsp;和&nbsp;<code>Password</code>&nbsp;用于加载 .pem/<em>.crt</em>&nbsp;和 .key 文件。</li>
<li><code>Subject</code>&nbsp;和&nbsp;<code>Store</code>&nbsp;用于从证书存储中加载。</li>
</ul>
<hr>
<p>好了,罗嗦话说完了,我们抽取文档的一部分进行实践</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> builder =<span style="color: rgba(0, 0, 0, 1)"> WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(serverOptions </span>=&gt;<span style="color: rgba(0, 0, 0, 1)">
{
    serverOptions.ListenAnyIP(</span><span style="color: rgba(128, 0, 128, 1)">5005</span>, listenOptions =&gt;<span style="color: rgba(0, 0, 0, 1)">
    {
      listenOptions.UseHttps(httpsOptions </span>=&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> localhostCert =<span style="color: rgba(0, 0, 0, 1)"> CertificateLoader.LoadFromStoreCert(
                </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">localhost</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">My</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, StoreLocation.CurrentUser,
                allowInvalid: </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> exampleCert =<span style="color: rgba(0, 0, 0, 1)"> CertificateLoader.LoadFromStoreCert(
                </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">example.com</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">My</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, StoreLocation.CurrentUser,
                allowInvalid: </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> subExampleCert =<span style="color: rgba(0, 0, 0, 1)"> CertificateLoader.LoadFromStoreCert(
                </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">sub.example.com</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">My</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, StoreLocation.CurrentUser,
                allowInvalid: </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> certs = <span style="color: rgba(0, 0, 255, 1)">new</span> Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>, X509Certificate2&gt;<span style="color: rgba(0, 0, 0, 1)">(
                StringComparer.OrdinalIgnoreCase)
            {
                [</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">localhost</span><span style="color: rgba(128, 0, 0, 1)">"</span>] =<span style="color: rgba(0, 0, 0, 1)"> localhostCert,
                [</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">example.com</span><span style="color: rgba(128, 0, 0, 1)">"</span>] =<span style="color: rgba(0, 0, 0, 1)"> exampleCert,
                [</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">sub.example.com</span><span style="color: rgba(128, 0, 0, 1)">"</span>] =<span style="color: rgba(0, 0, 0, 1)"> subExampleCert
            };

            httpsOptions.ServerCertificateSelector </span>= (connectionContext, name) =&gt;<span style="color: rgba(0, 0, 0, 1)">
            {
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (name <span style="color: rgba(0, 0, 255, 1)">is</span> not <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; certs.TryGetValue(name, <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> cert))
                {
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> cert;
                }

                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> exampleCert;
            };
      });
    });
});</span></pre>
</div>
<p>  上面的代码一看就能懂,比较无奈的是官方文档的 SSL 证书是从&nbsp;证书存储区 里获取的,在实际应用中,明显是不够方便,最好是那种直接写 证书路径 和 密码的,这样才能一目了然嘛,而这里的关键就是&nbsp;X509Certificate2 这个类了,可以看到,最终是通过检索一个字典返回的,接受的就是这个&nbsp;X509Certificate2 类,所以我们看看这个类到底是个什么东西,传送门;</p>
<p>  这里我们只关注构造函数,下面是官方文档,或者直接 F12 进去看更为直接</p>
<hr>
<p>&nbsp;</p>
<p id="constructors" class="heading-anchor"><strong><span style="font-size: 18px">构造函数</span></strong></p>
<table class="nameValue table table-sm table-stacked-mobile">
<tbody>
<tr>
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2()</span></td>
<td class="summary">
<div data-moniker=" net-6.0 net-7.0 ">已过时。</div>
<p>初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr>
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(Byte[])</span></td>
<td class="summary">
<p>使用来自字节数组的信息初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr data-moniker=" net-5.0 net-6.0 net-7.0 netcore-2.0 netcore-2.1 netcore-2.2 netcore-3.0 netcore-3.1 netframework-2.0 netframework-3.0 netframework-3.5 netframework-4.0 netframework-4.5 netframework-4.5.1 netframework-4.5.2 netframework-4.6 netframework-4.6.1 netframework-4.6.2 netframework-4.7 netframework-4.7.1 netframework-4.7.2 netframework-4.8 netstandard-2.0 netstandard-2.1 xamarinandroid-7.1 xamarinios-10.8 xamarinmac-3.0 ">
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(Byte[], SecureString)</span></td>
<td class="summary">
<p>使用一个字节数组和一个密码初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr data-moniker=" net-5.0 net-6.0 net-7.0 netcore-2.0 netcore-2.1 netcore-2.2 netcore-3.0 netcore-3.1 netframework-2.0 netframework-3.0 netframework-3.5 netframework-4.0 netframework-4.5 netframework-4.5.1 netframework-4.5.2 netframework-4.6 netframework-4.6.1 netframework-4.6.2 netframework-4.7 netframework-4.7.1 netframework-4.7.2 netframework-4.8 netstandard-2.0 netstandard-2.1 xamarinandroid-7.1 xamarinios-10.8 xamarinmac-3.0 ">
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(Byte[], SecureString, X509KeyStorageFlags)</span></td>
<td class="summary">
<p>使用一个字节数组、一个密码和一个密钥存储标志初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr>
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(Byte[], String)</span></td>
<td class="summary">
<p>使用一个字节数组和一个密码初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr>
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(Byte[], String, X509KeyStorageFlags)</span></td>
<td class="summary">
<p>使用一个字节数组、一个密码和一个密钥存储标志初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr>
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(IntPtr)</span></td>
<td class="summary">
<p>使用非托管句柄初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr data-moniker=" net-5.0 net-6.0 net-7.0 ">
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(ReadOnlySpan&lt;Byte&gt;)</span></td>
<td class="summary">
<p>用证书数据初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr data-moniker=" net-5.0 net-6.0 net-7.0 ">
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(ReadOnlySpan&lt;Byte&gt;, ReadOnlySpan&lt;Char&gt;, X509KeyStorageFlags)</span></td>
<td class="summary">
<p>使用证书数据、密码和密钥存储标志初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr data-moniker=" net-5.0 net-6.0 net-7.0 netcore-2.0 netcore-2.1 netcore-2.2 netcore-3.0 netcore-3.1 netframework-4.0 netframework-4.5 netframework-4.5.1 netframework-4.5.2 netframework-4.6 netframework-4.6.1 netframework-4.6.2 netframework-4.7 netframework-4.7.1 netframework-4.7.2 netframework-4.8 netstandard-2.0 netstandard-2.1 xamarinandroid-7.1 xamarinios-10.8 xamarinmac-3.0 ">
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(SerializationInfo, StreamingContext)</span></td>
<td class="summary">
<p>使用指定的序列化和流上下文信息初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr>
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(String)</span></td>
<td class="summary">
<p>使用证书文件名初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr data-moniker=" net-5.0 net-6.0 net-7.0 ">
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(String, ReadOnlySpan&lt;Char&gt;, X509KeyStorageFlags)</span></td>
<td class="summary">
<p>使用一个证书文件名、一个密码和一个密钥存储标志初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr data-moniker=" net-5.0 net-6.0 net-7.0 netcore-2.0 netcore-2.1 netcore-2.2 netcore-3.0 netcore-3.1 netframework-2.0 netframework-3.0 netframework-3.5 netframework-4.0 netframework-4.5 netframework-4.5.1 netframework-4.5.2 netframework-4.6 netframework-4.6.1 netframework-4.6.2 netframework-4.7 netframework-4.7.1 netframework-4.7.2 netframework-4.8 netstandard-2.0 netstandard-2.1 xamarinandroid-7.1 xamarinios-10.8 xamarinmac-3.0 ">
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(String, SecureString)</span></td>
<td class="summary">
<p>使用一个证书文件名和一个密码初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr data-moniker=" net-5.0 net-6.0 net-7.0 netcore-2.0 netcore-2.1 netcore-2.2 netcore-3.0 netcore-3.1 netframework-2.0 netframework-3.0 netframework-3.5 netframework-4.0 netframework-4.5 netframework-4.5.1 netframework-4.5.2 netframework-4.6 netframework-4.6.1 netframework-4.6.2 netframework-4.7 netframework-4.7.1 netframework-4.7.2 netframework-4.8 netstandard-2.0 netstandard-2.1 xamarinandroid-7.1 xamarinios-10.8 xamarinmac-3.0 ">
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(String, SecureString, X509KeyStorageFlags)</span></td>
<td class="summary">
<p>使用一个证书文件名、一个密码和一个密钥存储标志初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr>
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(String, String)</span></td>
<td class="summary">
<p>使用一个证书文件名和一个用于访问该证书的密码初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr>
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(String, String, X509KeyStorageFlags)</span></td>
<td class="summary">
<p>使用一个证书文件名、一个用于访问该证书的密码和一个密钥存储标志初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
</td>
</tr>
<tr data-moniker=" net-5.0 net-6.0 net-7.0 netcore-2.0 netcore-2.1 netcore-2.2 netcore-3.0 netcore-3.1 netframework-2.0 netframework-3.0 netframework-3.5 netframework-4.0 netframework-4.5 netframework-4.5.1 netframework-4.5.2 netframework-4.6 netframework-4.6.1 netframework-4.6.2 netframework-4.7 netframework-4.7.1 netframework-4.7.2 netframework-4.8 netstandard-2.0 netstandard-2.1 xamarinandroid-7.1 xamarinios-10.8 xamarinmac-3.0 ">
<td class="is-one-third-width-tablet"><span class="break-text">X509Certificate2(X509Certificate)</span></td>
<td class="summary">
<p>使用&nbsp;X509Certificate&nbsp;对象初始化&nbsp;X509Certificate2&nbsp;类的新实例。</p>
<div>&nbsp;</div>
</td>
</tr>
</tbody>
</table>
<hr>
<p>  直接 F12 也贴出来吧,方便大伙查看</p>
<p><img src="https://img2022.cnblogs.com/blog/1897432/202209/1897432-20220922235127616-1962596990.png" alt="" loading="lazy" style="display: block; margin-left: auto; margin-right: auto"></p>
<p>&nbsp;</p>
<p>&nbsp;  帅气的小伙伴可能已经发现了,里面就存在了一个 直接传入 文件路径 和 密码 作为参数的构造函数,毫无疑问,它就是我们要找的!!!下面我们直接看代码:</p>
<p>Program.cs</p>
<div class="cnblogs_code">
<pre>builder.WebHost.ConfigureKestrel(serverOptions =&gt;<span style="color: rgba(0, 0, 0, 1)">
{
    serverOptions.ConfigureHttpsDefaults(listenOptions </span>=&gt;<span style="color: rgba(0, 0, 0, 1)">
    {
      listenOptions.SslProtocols </span>=<span style="color: rgba(0, 0, 0, 1)"> SslProtocols.Tls13;
    });
    serverOptions.ListenAnyIP(</span><span style="color: rgba(128, 0, 128, 1)">5209</span>, listenOptions =&gt;<span style="color: rgba(0, 0, 0, 1)">
    {
      listenOptions.UseHttps(httpsOptions </span>=&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> test1 = <span style="color: rgba(0, 0, 255, 1)">new</span> X509Certificate2(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">cer\\test1.ysmc.net.cn_server.pfx</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">密码1</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> test2 = <span style="color: rgba(0, 0, 255, 1)">new</span> X509Certificate2(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">cer\\test2.ysmc.net.cn_server.pfx</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">密码2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> certs = <span style="color: rgba(0, 0, 255, 1)">new</span> Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>, X509Certificate2&gt;<span style="color: rgba(0, 0, 0, 1)">(
                StringComparer.OrdinalIgnoreCase)
            {
                [</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">test1.ysmc.net.cn</span><span style="color: rgba(128, 0, 0, 1)">"</span>] =<span style="color: rgba(0, 0, 0, 1)"> test1,
                [</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">test2.ysmc.net.cn</span><span style="color: rgba(128, 0, 0, 1)">"</span>] =<span style="color: rgba(0, 0, 0, 1)"> test2
            };

            httpsOptions.ServerCertificateSelector </span>= (connectionContext, name) =&gt;<span style="color: rgba(0, 0, 0, 1)">
            {
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (name <span style="color: rgba(0, 0, 255, 1)">is</span> not <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; certs.TryGetValue(name, <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> cert))
                {
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> cert;
                }

                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> test1;
            };
      });
    });
});</span></pre>
</div>
<p><img src="https://img2022.cnblogs.com/blog/1897432/202209/1897432-20220922235603097-643993874.png" alt="" loading="lazy" style="display: block; margin-left: auto; margin-right: auto"></p>
<p>&nbsp;</p>
<p>  因为是配合了 YARP “食用”的,详情可以查看我前面的文章,传送门,所以不同的域名会反向代理到不同的网站上面,好了,文章到此结束,感谢大佬们的阅读,谢谢!</p>
<p>原文链接:https://www.cnblogs.com/ysmc/p/16721268.html</p>

</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:一事冇诚,转载请注明原文链接:https://www.cnblogs.com/ysmc/p/16721268.html</p><br><br>
来源:https://www.cnblogs.com/ysmc/p/16721268.html
頁: [1]
查看完整版本: .NET 部署 多域名 Https(SSL)通过代码方式