在一般的系統中,往往也有短信模塊的需求,如動態密碼的登錄,系統密碼的找回,以及為了獲取用戶手機號碼的短信確認等等,在ABP框架中,本身提供了對郵件、短信的基礎支持,那么只需要根據自己的情況實作對應的介面即可,本篇隨筆介紹ABP框架中短信發送處理,包括阿里云短信和普通短信商的短信發送集成,
1、基于第三方阿里云短信的實作
阿里云短信的實作,GitHub上也有一些人實作了一些模塊,我們只需要使用對應的模塊,然后在Core模塊中配置一下依賴即可,
我們一般在做某件事情的時候,先去看看別人是否已經做好了,使用它或者參考它來做事情是個不錯的思路,
基于這個道理,我們可以在VS的Nuget包管理中查找一下基于ABP的阿里云短信,可以找到一個合適的進行參考,

這個阿里云的ABP實作適合我們當前的ABP框架版本,因此使用它即可,因此安裝引入對應的類別庫在Core專案中,

在網站https://github.com/tangyanglai/Sms.Core 我們看到它的使用程序,引入后在專案中啟動模塊依賴中添加對應的代碼即可,
[DependsOn(typeof(AliyunSmsModule))]
那么我們在專案中的代碼如下所示

默認支持兩種配置方式,組態檔和SettingManager,下面以組態檔為例,格式為:
{ "AliyunSmsSettings": { "AccessKeyId": "", "AccessKeySecret": "", "SignName": "", //SendCodeAsync發送驗證碼使用 "TemplateCode": "" , //SendCodeAsync發送驗證碼使用 } }
根據上面的說明,我們在Host專案的AppSettings.json中增加對應的阿里云配置項,如下所示,

其中AccessKeyId是標識用戶身份的ID,AccessKeySecret 是秘鑰,SigName是我們申請的短信商戶簽名,TemplateCode是我們驗證碼的配置

而短信一般是基于某個模板進行發送的,因此需要確定系統使用的短信模板,

阿里云的發送模塊是使用ISmsTemplateSender進行發送的,因此在代碼中使用如下所示,
那么在使用發送短信驗證碼的地方,如AccountService應用層中,使用的時候使用它的注入介面即可發送短信驗證碼了,

使用發送短信的操作如下所示,
/// <summary> /// 發送短信驗證碼 /// </summary> /// <param name="phone">手機號碼</param> /// <param name="code">驗證碼</param> /// <returns></returns> public async Task<SmsResult> SendCodeAsync(string phone, string code) { return await _smsTemplateSender.SmsService.SendCodeAsync(phone, code); } /// <summary> /// 發送模板訊息 /// </summary> /// <param name="input">模板物件</param> /// <returns></returns> public async Task<SmsResult> SendTemplateMessageAsync(SendTemplateMessageInput input) { return await _smsTemplateSender.SmsService.SendTemplateMessageAsync(input); }
2、使用自己的阿里云短信發送封裝
我之前隨筆《使用阿里云的短信服務發送短信》中寫過如何處理阿里云短信,雖然那個是常規.net framework的程式中集成的,不過在.net Core的代碼都是差不多的,
我們知道ABP框架提供了對應的短信發送介面,一般注入在系統中使用即可,
namespace MyProject.Net { /// <summary> /// 短信發送介面 /// </summary> public interface ISmsSender { Task<CommonResult> SendAsync(string number, string message); } }
那么我們自己定義的短信發送介面,實作它即可,然后注入使用對應的介面即可,
根據阿里云介面需求,定義一個類似的模型用作加載引數的,
/// <summary> /// 阿里云配置引數 /// </summary> internal class AliyunSmsSettting { public string AccessKeyId { get; set; } public string AccessKeySecret { get; set; } public string RegionId { get; set; } public string EndpointName { get; set; } public string Domain { get; set; } public string Product { get; set; } public string SignName { get; set; } public string TemplateCode { get; set; } public string TemplateParam { get; set; } }
然后讓我們的介面實作函式,初始化的時候獲取對應的配置資訊供使用,
{ /// <summary> /// 使用簡單封裝,不依賴其他外部模塊的阿里云短信發送 /// </summary> public class AliyunSmsSender : IShouldInitialize, ISmsSender, ITransientDependency { public IConfiguration AppConfiguration { get; set; } public IIocManager IocManager { get; set; } public ILogger Logger { get; set; } private const string Key = "AliyunSmsSettings"; private const string endpoint = "dysmsapi.aliyuncs.com"; /// <summary> /// 短信配置資訊 /// </summary> private AliyunSmsSettting SmsSettings { get; set; } public AliyunSmsSender(IConfiguration appConfiguration, IIocManager iocManager) { this.AppConfiguration = appConfiguration; this.IocManager = iocManager; this.Logger = NullLogger.Instance; } public void Initialize() { this.SmsSettings = GetConfigFromConfigOrSettingsByKey<AliyunSmsSettting>().Result; }
然后根據我之前隨筆的實作邏輯,給他實作對應的發送操作即可,部分關鍵代碼如下所示
/// <summary> /// 發送短信 /// </summary> /// <param name="number">手機號碼</param> /// <param name="message">訊息或驗證碼</param> /// <returns></returns> public async Task<CommonResult> SendAsync(string number, string message) { var result = await PrivateSend(number, message); return result; } /// <summary> /// 發送邏輯 /// </summary> /// <returns></returns> private async Task<CommonResult> PrivateSend(string number, string code) { string nowDate = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'");//GTM時間 var keyValues = new Dictionary<string, string>();//宣告一個字典 //1.系統引數 keyValues.Add("SignatureMethod", "HMAC-SHA1"); keyValues.Add("SignatureNonce", Guid.NewGuid().ToString()); keyValues.Add("AccessKeyId", this.SmsSettings.AccessKeyId); keyValues.Add("SignatureVersion", "1.0"); keyValues.Add("Timestamp", nowDate); keyValues.Add("Format", "Json");//可換成xml //2.業務api引數 keyValues.Add("Action", "SendSms"); keyValues.Add("Version", "2017-05-25"); keyValues.Add("RegionId", "cn-hangzhou"); keyValues.Add("PhoneNumbers", number); keyValues.Add("SignName", this.SmsSettings.SignName); keyValues.Add("TemplateCode", this.SmsSettings.TemplateCode); keyValues.Add("TemplateParam", string.Format("{{\"code\":\"{0}\"}}", code)); keyValues.Add("OutId", "123"); //3.去除簽名關鍵字key if (keyValues.ContainsKey("Signature")) { keyValues.Remove("Signature"); } //4.引數key排序 Dictionary<string, string> ascDic = keyValues.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value.ToString()); //5.構造待簽名的字串 var builder = new StringBuilder(); foreach (var item in ascDic) { if (item.Key == "SignName") { } else { builder.Append("&").Append(specialUrlEncode(item.Key)).Append("=").Append(specialUrlEncode(item.Value)); } if (item.Key == "RegionId") { builder.Append("&").Append(specialUrlEncode("SignName")).Append("=").Append(specialUrlEncode(keyValues["SignName"])); } } string sorteQueryString = builder.ToString().Substring(1); StringBuilder stringToSign = new StringBuilder(); stringToSign.Append("GET").Append("&"); stringToSign.Append(specialUrlEncode("/")).Append("&"); stringToSign.Append(specialUrlEncode(sorteQueryString)); string Sign = MySign(this.SmsSettings.AccessKeySecret + "&", stringToSign.ToString()); //6.簽名最后也要做特殊URL編碼 string signture = specialUrlEncode(Sign); //最終列印出合法GET請求的URL string url = string.Format("http://{0}/?Signature={1}{2}", endpoint, signture, builder); var modal = await GetHtmlResult(url); return new CommonResult(modal.Success, modal.Message); }
然后在Core模塊中初始化的時候,替換對應的短信發送實作即可,

這樣就可以使用我們自己的短信介面了

發送代碼如下所示
/// <summary> /// 發送短信驗證碼 /// </summary> /// <param name="phone">手機號碼</param> /// <param name="code">驗證碼</param> /// <returns></returns> public async Task<CommonResult> SendSmsCodeAsync(string phone, string code) { return await _smsSender.SendAsync(phone, code); //使用阿里云介面 }
3、普通短信商的短信發送集成
還有一種我們可能不是基于阿里云,而是其他提供商的介面發送,操作也是自定義短信介面的封裝,
我們使用如下引數來確定短信提供商的資訊,也可以根據需要自己調整,

定義一個配置對應的配置物件,方便獲取引數資訊,
/// <summary> /// 自定義短信配置 /// </summary> internal class MySmsSettings { /// <summary> /// 供應商代碼 /// </summary> public string spcode { get; set; } /// <summary> /// 賬戶 /// </summary> public string username { get; set; } /// <summary> /// 密碼 /// </summary> public string password { get; set; } }

由于我們這個的實作也是基于標準介面ISmsSender的,那么我們實作這個后,也需要特定指定這個實作為ISmsSender的使用,
例如在CoreModule中替換為這個短信實作的話,如下代碼,
//使用自定義的 ISmsSender Configuration.ReplaceService<ISmsSender, MySmsSender>();
使用介面發送短信的時候,就和我們上面的操作類似的了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/244998.html
標籤:.NET Core
