添加certes与AlibabaCloud.SDK.Alidns20150109包
如下图
检查证书是否过期
var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(filePath, password); DateTime expirationDate = cert.NotAfter; if (expirationDate.AddDays(-1).Date <= DateTime.Now.Date) { //更新证书 await SSLHelper.GetPfxByACMEAsync(item, password, accessKeyId, accessKeySecret); }更新证书源码
public static async Task GetPfxByACMEAsync(string domain, string password,string accessKeyId,string accessKeySecret) { string domainName = domain; var acme = new AcmeContext(WellKnownServers.LetsEncryptV2); try { var account = await acme.NewAccount("随意填一个你的邮箱帐号即可,例如:test@163.com", true); var order = await acme.NewOrder(new[] { domainName }); var authz = (await order.Authorizations()).First(); var dnsChallenge = await authz.Dns(); var dnsTxt = acme.AccountKey.DnsTxt(dnsChallenge.Token); //创键dns var config = new AlibabaCloud.OpenApiClient.Models.Config { // 建议使用环境变量配置 AccessKey,提高安全性 AccessKeyId = accessKeyId, AccessKeySecret = accessKeySecret, // 云解析DNS的Endpoint Endpoint = "alidns.aliyuncs.com" }; var client = new AlibabaCloud.SDK.Alidns20150109.Client(config); var request = new AddDomainRecordRequest { DomainName = domainName, RR = "_acme-challenge", Type = "TXT", Value = dnsTxt, TTL = 600 }; var response = client.AddDomainRecord(request); var validateResult = await dnsChallenge.Validate(); if (validateResult.Status != Certes.Acme.Resource.ChallengeStatus.Valid) { var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); while (!cts.Token.IsCancellationRequested) { await Task.Delay(1000, cts.Token); // 重新获取最新状态 var currentChallenge = await dnsChallenge.Resource(); if (currentChallenge.Status == Certes.Acme.Resource.ChallengeStatus.Valid) { break; } } } var privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256); var cert = await order.Generate(new CsrInfo { CommonName = domainName, }, privateKey); var certificateChain = await order.Download(); var pfxBuilder = certificateChain.ToPfx(privateKey); pfxBuilder.FullChain = false; var deleteRequest = new DeleteDomainRecordRequest { RecordId = response.Body.RecordId }; client.DeleteDomainRecord(deleteRequest); var pfx = pfxBuilder.Build($"{domainName}.pfx", password); System.IO.File.WriteAllBytes($"{domainName}.pfx", pfx); } catch (TeaException ex) { throw new Exception($"ACME获取证书错误: {ex.Message}", ex); } }关于accessKeyId与accessKeySecret生成参考下面链接
阿里云密钥参考
ABP添加定时任务每天检查过期
public class SSLCheckerWorker : AsyncPeriodicBackgroundWorkerBase { private readonly IConfiguration _configuration; public SSLCheckerWorker(AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory, IConfiguration configuration) : base(timer, serviceScopeFactory) { _configuration = configuration; // 每天凌晨 2:00 执行一次 Timer.Cron = "0 2 * * *"; } protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext) { // 执行每日任务 var domains = _configuration["Acme:Domains"]; if (!string.IsNullOrEmpty(domains)) { var password = _configuration["Acme:password"]; var accessKeyId = _configuration["Aliyun:accessKeyId"]; var accessKeySecret = _configuration["Aliyun:secret"]; // 构建域名到证书文件的映射 var domainMap = domains.Split(';', StringSplitOptions.RemoveEmptyEntries); foreach (var item in domainMap) { string filePath = $"{item}.pfx"; var checkFile = System.IO.File.Exists(filePath); if (checkFile) { 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 SSLHelper.GetPfxByACMEAsync(item, password, accessKeyId, accessKeySecret); } } } } await Task.CompletedTask; } }在OnApplicationInitialization添加后台任务
配置文件参考