一个站点对应多个域名,所以要有多个证书
打开Host下面Program.cs,加入代码,如下图
Kestrel 的证书支持热更新机制,新的证书文件覆盖后会自动更新
cs
//下面代码作用是证书文件更新后,自动更新证书,不需要重启应用
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(httpsOptions =>
{
httpsOptions.ServerCertificateSelector = (connectionContext, name) =>
{
return name?.ToLower() switch
{
"域名1.com" or "www.域名1.com" => new X509Certificate2("证书1.pfx", "密码"),
"域名2.net" or "www.域名2.net" => new X509Certificate2("证书2.pfx", "密码"),
_ => throw new NotSupportedException($"No certificate available for {name}")
};
};
});
});

如果你只有一个域名,代码如下:
cs
httpsOptions.ServerCertificateSelector = (ctx, host) =>
{
// 可用代码动态读取最新的证书
return new X509Certificate2("/path/to/your/cert.pfx", "your_cert_password");
};
自动更新算法
1、程序启动时判断证书过期,程序启动后每天定时检查证书过期
2、过期后从阿里云自动下载文件覆盖本地文件即可。
自动下载证书参考我上次的文章,参考地址如下
net9阿里云自动申请ssl证书,下载证书pfx格式-CSDN博客
判断证书是否过期代码
cs
var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2("证书文件", "密码");
DateTime expirationDate = DateTime.Parse(cert.GetExpirationDateString());
if (expirationDate.AddDays(-1).Date <= DateTime.Now.Date)
{
//下载证书
}
多个证书过期判断
cs
// 搜索所有.pfx文件
string[] pfxFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.pfx", SearchOption.AllDirectories);
foreach (var filePath in pfxFiles)
{
var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(filePath, "密码");
DateTime expirationDate = DateTime.Parse(cert.GetExpirationDateString());
if (expirationDate.AddDays(-1).Date <= DateTime.Now.Date)
{
//下载证书
}
}
完整的代码如下:
接口IOpenSSLAppService,目的是为了兼容其它云平台域名证书

cs
/// <summary>
/// 检查证书是否过期
/// </summary>
/// <returns></returns>
public async Task IsCertificateExpiredAsync()
{
// 搜索所有.pfx文件
string[] pfxFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.pfx", SearchOption.AllDirectories);
string password = _configuration["Aliyun:password"];
foreach (var filePath in pfxFiles)
{
var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(filePath, password);
DateTime expirationDate = DateTime.Parse(cert.GetExpirationDateString());
if (expirationDate.AddDays(-1).Date <= DateTime.Now.Date)
{
//更新证书
await GetPfxAsync(filePath.GetFileNameWithoutExtension(), password);
}
}
}
/// <summary>
/// 获取域名证书
/// </summary>
/// <param name="domain"></param>
/// <param name="password"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task GetPfxAsync(string domain,string password)
{
var akConfig = new Aliyun.Credentials.Models.Config
{
Type = "access_key",
AccessKeyId = _configuration["Aliyun:accessKeyId"],
AccessKeySecret = _configuration["Aliyun:secret"]
};
var akCredential = new Aliyun.Credentials.Client(akConfig);
AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config
{
Credential = akCredential,
RegionId = _configuration["Aliyun:regionId"]
};
AlibabaCloud.SDK.Cas20200407.Client client = new AlibabaCloud.SDK.Cas20200407.Client(config);
try
{
var request = new CreateCertificateRequestRequest
{
Username = _configuration["Aliyun:mail"],
Phone = _configuration["Aliyun:phone"],
Email = _configuration["Aliyun:mail"],
Domain = domain,
ValidateType = "DNS"
};
var runtime = new RuntimeOptions();
var certificateResponse = await client.CreateCertificateRequestAsync(request);
DescribeCertificateStateResponse certificateStateResponse;
if (certificateResponse.StatusCode == 200 && certificateResponse.Body != null)
{
var orderId = certificateResponse.Body.OrderId;
certificateStateResponse = await client.DescribeCertificateStateAsync(new DescribeCertificateStateRequest { OrderId = orderId });
while (certificateStateResponse.Body.PrivateKey == null)
{
Thread.Sleep(30000);//休息30秒
certificateStateResponse = await client.DescribeCertificateStateAsync(new DescribeCertificateStateRequest { OrderId = orderId });
}
if (certificateStateResponse.Body.PrivateKey != null)
{
//保存证书
string certPem = certificateStateResponse.Body.Certificate; // 公钥证书 PEM 字符串
string keyPem = certificateStateResponse.Body.PrivateKey; // 私钥 PEM 字符串
CryptorHelper.PemToPfx(certPem, keyPem, $"{domain}.pfx", password);
}
}
}
catch (TeaException ex)
{
throw new Exception($"阿里云API错误: {ex.Message}", ex);
}
}
添加程序启动更新代码

加入到hangfire定时任务,每天1点检查,定时更新

