在一般的系统中,往往也有短信模块的需求,如动态密码的登录,系统密码的找回,以及为了获取用户手机号码的短信确认等等,在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>();

使用接口发送短信的时候,就和我们上面的操作类似的了。

ABP框架中短信发送处理,包括阿里云短信和普通短信商的短信发送集成的更多相关文章

  1. 阿里云短信验证_基于阿里云OpenAPI实现

    阿里云短信服务 背景简介: 短信验证以及短信通知,目前已经应用的非常广泛,最近因项目需要,需要将原来的短信接口换成阿里云的的短信服务,原项目集成的短信服务能够实现短信的发送以及短信的验证整个过程,简单 ...

  2. 移动端获取短信验证码java实现——阿里云短信服务

    需求:移动端输入手机号,获取验证码.点击登录,验证验证码是否输入错误.是否超时等情况,一旦校验通过,将用户数据保存到数据中(业务逻辑). 前提:注册阿里用户,开通短信服务,申请key.秘钥.签名.短信 ...

  3. 浏览器端获取短信验证码java实现——阿里云短信服务

    需求:浏览器端输入手机号,获取验证码.点击登录,验证验证码是否输入错误.是否超时等情况,一旦校验通过,将用户数据保存到数据中(业务逻辑). 前提:注册阿里用户,开通短信服务,申请key.秘钥.签名.短 ...

  4. composer阿里云短信服务不支持传参为数值--为2017年短信接口,2018阿里云有更新http://www.cnblogs.com/q1104460935/p/8916096.html

    composer 阿里云短信服务使用 xuying/aliyun_mns     更新到2017年初,不再更新 ){;, ); }; } ; }; }; }} 以下为发送成功返回对象 object(A ...

  5. TPshop之短信注册配置(阿里云)

      短信注册准备: 1.阿里云账号实名认证(申请地址: https://www.aliyun.com/ , 注意不是阿里大于短信平台) 步骤: 注册登录阿里云——找到控制台 ​ 鼠标放在左上角,弹出菜 ...

  6. Delphi阿里云邮件推送【支持单一发信、邮件批量发送和获取指定条件下的发送数据】

    作者QQ:(648437169) 点击下载➨Delphi阿里云邮件推送               阿里云api文档 [Delphi阿里云邮件推送]支持SingleSendMail(单一发信接口). ...

  7. Spring框架学习笔记(6)——阿里云服务器部署Spring Boot项目(jar包)

    最近接外包,需要部署服务器,便是参考了网上的几篇博文,成功在阿里云服务器成功部署了Spring Boot项目,特记下本篇笔记 Spring Boot项目打包 这里说一下部署的一些问题 1.mysql驱 ...

  8. open suse 42.3常用软件源(包括阿里云)

    阿里镜像源,直接在终端安装,首先在终端输入 su 点击回车,输入密码,密码输入时为了安全是不显示的,你输入以后直接回车就可以了. zypper addrepo -f http://mirrors.al ...

  9. flask+阿里云短信服务实现注册发送手机验证码

    效果图: 该效果主要讲解实现通过调用阿里云的SDK实现发送注册验证码短信(阿里云短信付费使用) 购买阿里云短信服务 购买链接:https://www.aliyun.com/product/sms 1. ...

随机推荐

  1. 老猿学5G扫盲贴:中国移动5G融合计费漫游计费架构和路由方案

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt+moviepy音视频剪辑实战 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一. ...

  2. PyQt(Python+Qt)学习随笔:QScrollArea的alignment属性不起作用的原因

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 Scroll Area滚动区域提供了一个呈现在其他部件上的可滚动区域视图,对应类为QScrollAr ...

  3. 深入理解python

    1 python自身的威力 1.1 使用type.str.dir.其他内置函数 //type函数:返回任意对象的数据类型.比如:整型.字符串.列表.字典.元组.函数.类.模块,甚至类型对象都可以作为参 ...

  4. 浅谈php反序列化漏洞

    关于php的反序列化漏洞要先说到序列化和反序列化的两个函数,即: serialize() 和unserialize(). 简单的理解: 序列化就是将一个对象变成字符串 反序列化是将字符串恢复成对象 这 ...

  5. Day2 Scrum 冲刺博客

    线上会议: 昨天已完成的工作与今天计划完成的工作及工作中遇到的困难: 成员姓名 昨天完成工作 今天计划完成的工作 工作中遇到的困难 纪昂学 总结会议内容,思考自己所分配到的任务 创建一个Cell类,用 ...

  6. 区块链产业发展热潮来袭,Panda Global 认为体验、安全是关键词

    作为一项近些年才发展起来的新型技术,区块链自诞生之日起就备受关注,凭着去中心化.不可篡改.信息透明等多种关键特点,已成为变革传统产业的一项有力创新手段.当区块链热潮再度袭来之时,知名数字货币交易所Pa ...

  7. Java集合源码分析(七)——TreeMap

    简介 TreeMap 是一个有序的key-value集合,它的内部是通过红黑树实现的. TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合. TreeMap ...

  8. STL——容器(Map & multimap)的大小

    1. Map & multimap 的大小 map.size();     //返回容器中元素的数目 map.empty();//判断容器是否为空, 容器中有内容将会返回 false 代码示例 ...

  9. 安卓qq视频动态名片制作器

    本软件来自互联网,仅供个人参考,严禁商业用途! 非常炫酷的diy动态名片教程,B格绝对高,内含软件教程代码,包会!

  10. Jmeter(1)下载和安装

    一.Jmeter工具安装 1.jmeter安装包下载地址:http://jmeter.apache.org/,下载Binaries包,使用jmeter需要先安装jdk 2.解压后打开/bin目录下的j ...