_ = LCSMSClient.verifyMobilePhoneNumber("18200008888", verificationCode: "123456") { (result) in
switch result {
case .success:
break
case .failure(error: let error):
print(error)
}
}
LCSMS.verifySMSCodeInBackground("123456","18200008888").subscribe(new Observer<LCNull>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(LCNull avNull) {
Log.d("TAG","Result: Successfully verified the number.");
}
@Override
public void onError(Throwable throwable) {
Log.d("TAG","Result: Failed to verify the number. Reason: " + throwable.getMessage());
}
@Override
public void onComplete() {
}
});
_ = LCSMSClient.requestVoiceVerificationCode(mobilePhoneNumber: "18200008888") { (result) in
switch result {
case .success:
break
case .failure(error: let error):
print(error)
}
}
LCSMSOption option = new LCSMSOption();
option.setType(LCSMS.TYPE.VOICE_SMS);
LCSMS.requestSMSCodeInBackground("18200008888", option).subscribe(new Observer<LCNull>() {
@Override
public void onSubscribe(Disposable disposable) {
}
@Override
public void onNext(LCNull avNull) {
Log.d("TAG","Result: Successfully made a call.");
}
@Override
public void onError(Throwable throwable) {
Log.d("TAG","Result: Failed to make a call. Reason: " + throwable.getMessage());
}
@Override
public void onComplete() {
}
});
_ = LCSMSClient.verifyMobilePhoneNumber("18200008888", verificationCode: "123456") { (result) in
switch result {
case .success:
break
case .failure(error: let error):
print(error)
}
}
LCSMS.verifySMSCodeInBackground("123456","18200008888").subscribe(new Observer<LCNull>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(LCNull avNull) {
Log.d("TAG","Result: Successfully verified the number.");
}
@Override
public void onError(Throwable throwable) {
Log.d("TAG","Result: Failed to verify the number. Reason: " + throwable.getMessage());
}
@Override
public void onComplete() {
}
});
var env = new Dictionary<string,object>()
{
{"order_id","7623432424540"} // 使用实际的值来替换模板中的变量
};
AVCloud.RequestSMSCodeAsync("18200008888","Order_Notice",env,"sign_BuyBuyBuy").ContinueWith(t =>
{
var result = t.Result;
// result 为 True 则表示调用成功
});
AV.Captcha.request().then(function (captcha) {
captcha.bind({
textInput: 'captcha-code', // The id for textInput
image: 'captcha-image', // The id for image element
verifyButton: 'verify' // The id for verify button
}, {
success: function (validateCode) {
console.log('验证成功,下一步');
},
error: function (error) {
console.error(error.message);
}
});
});
LCCaptchaClient.requestCaptcha(width: 100, height: 50) { (result) in
switch result {
case .success(value: let captcha):
if let url = captcha.url {
print(url)
}
if let token = captcha.token {
print(token)
}
case .failure(error: let error):
print(error)
}
}
LCCaptchaOption option = new LCCaptchaOption();
option.setWidth(85);
option.setHeight(30);
LCCaptcha.requestCaptchaInBackground(option).subscribe(new Observer<LCCaptchaDigest>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(LCCaptchaDigest avCaptchaDigest) {
Log.d("TAG","图片的 URL 是:" + avCaptchaDigest.getCaptchaUrl());
}
@Override
public void onError(Throwable throwable) {
Log.d("TAG","Result: Failed to request CAPTCHA. Reason: " + throwable.getMessage());
}
@Override
public void onComplete() {
}
});
LCCaptchaClient.verifyCaptcha(code: "code", captchaToken: "captcha.token") { (result) in
switch result {
case .success(value: let verification):
if let token = verification.token {
print(token)
}
case .failure(error: let error):
print(error)
}
}
短信 SMS 服务使用指南
短信服务适用的场景很多:
根据电信运营商的规范,短信按照用途被分为三类:
1. 验证类
【短信签名】您请求重设应用“应用名称”的密码,请输入验证码 123456 验证,验证码仅在 10 分钟内有效。
2. 通知类
【购物网】您尾号为34323的订单号已经通过宅急送(快递单号12343432)安排递送,请您开箱验货确认无误后签收,物流查询拨打400-0000-xxx。
3. 营销类
【当当】春风十里,好书陪你!30万种畅销书5折封顶!http://t.cn/Iekds 回TD退订
不同类型的短信遵循不同的 内容规范,不符合规定的短信将无法发送。
开发者在 LeanCloud 应用控制台开启与短信相关的服务后(参见 开通短信服务),即可通过 SDK 向用户发送短信:
用户收到的短信内容如下:
【LeanCloud】感谢您注册 LeanCloud,领先的 BaaS 提供商,为移动开发提供强有力的后端支持。
短信的内容来自名为
Register_Notice
的 模板,需要在控制台提前创建并通过审核。LeanCloud
为 短信签名名称,是必需添加的,也需要在控制台提前创建并通过审核才可使用。注意,这个参数的值是在控制台设置的短信签名名称,而不是短信签名本身。如果在控制台创建了多个名称相同的签名,那么最后创建的签名会覆盖之前创建的签名。利用这一特性可以实现不更改发送代码的前提下替换短信签名。
开通短信服务
在安全中心开启短信服务
要使用短信服务,首先需要在控制台创建一个应用,然后进入 控制台 > 设置 > 安全中心,确保 短信服务 开关是打开的:
完成短信配置
然后进入 控制台 > 短信 > 设置,请确保以下选项处于勾选状态:
✓启用通用的短信验证码服务(开放
requestSmsCode
和verifySmsCode
接口)设置默认签名
短信发送的时候需要有签名运营商才会放行,如前面示例中的「购物网」、「当当」即为短信签名。在开始发送短信之前,你需要进入 控制台 > 短信 > 签名与模版,设置默认的短信签名(第一个签名即为「默认签名」),详见短信签名一节的说明。
等签名审核完成之后,你就可以调用 LeanCloud API 发送自己的短信了。我们看到最开始的示例代码里面还有「短信模板」,但是因为并非所有类型的短信都需要用到模板,所以留待 后面详述。
验证类短信
通过短信进行注册、登录或重要操作的验证,是一种非常常见的需求。这里我们以一个购物应用为例,说明如何使用 LeanCloud 短信服务完成操作认证:
用户点击支付订单
发起敏感操作。
调用接口发送验证短信
注意,在这一步之前,我们假设开发者已经完成了前面章节提及的所有短信服务设置。
用户收到短信,并且输入了验证码
在进行下一步之前,我们建议先进行客户端验证(对有效性进行基本验证,例如长度、特殊字符等),这样就避免了错误的验证码被服务端驳回而产生的流量,以及与服务端沟通的时间,有助于提升用户体验。
调用接口验证用户输入的验证码是否有效
注意,调用时需要确保验证码和手机号的参数顺序,我们假设验证码数字是「123456」:
针对上述的需求,可以把场景换成异地登录验证、修改个人敏感信息验证等一些常见的场景,步骤是类似的,调用的接口也是一样的,仅仅是在做 UI 展现的时候需要开发者自己去优化验证过程。
语音短信验证码
文本短信验证码在到达率上有一定的风险。尽管根据我们长期得到的用户反馈,到达率已接近 100%,但是有些应用对时效性的要求极高,并且需要更好的安全性,所以我们也推出了语音短信验证码的服务,调用的方式如下:
发送成功之后,用户的手机就会收到一段语音通话,它会播报 6 位数的验证码,然后开发者需要再次调用:
再次验证用户输入的验证码是否正确。
营销、通知类短信
通知短信
通知类短信非常普遍,例如联通用户从外地进入上海可能会收到如下短信:
尊敬的用户:欢迎您来到上海,如需帮助请拨打客服热线10010或登录www.10010.com,优惠订购机票酒店请拨打116114。中国联通
这是一个来自通信运营商的通知类短信的规范案例。
营销短信
营销类短信是应用开发者与潜在客户沟通、进行产品推广和销售的有效手段。营销类短信使用时跟 通知短信 使用没有任何本质区别,步骤依次是 创建模板 > 使用模板。
营销类短信默认会在短信最后加上「回复TD退订」,这是运营商的强制要求。
自 2016 年 6 月起,营销类短信不允许由个人用户发送。所有营销类短信必须提供有效的公司或者企业名称,缺失名称将导致营销类短信无法发送。伪造或使用虚假名称将会被追究法律责任。
短信签名
短信签名是指短信内容里用【】括起来的短信发送方名称,根据运营商的规定,短信内容的开头必须有签名。 你需要在 控制台 > 短信 > 签名与模版 为每个应用创建合法的短信签名。 如果一个应用拥有多个短信签名,请确保选择其一作为 默认签名。
创建签名时需要输入内部名称和签名字符串,并上传相应的证明材料,如下图所示:
签名审核
为了确保短信内容的合法性及投递成功率,短信签名、短信模板需要经过 运营商人工审核 通过后,开发者才能在接口中调用该模板。根据我们的经验,短信模板、非营销类短信签名通常需要 1 个工作日,营销类签名审核时间较长,一般需要 2 – 5 个工作日。 如果提交签名、模板后长时间处于「审核中」状态,请提交工单或通过邮件(leancloud-support@xd.com)联系我们处理。
应运营商的审核要求,创建签名需要提交相应的证明材料,证明具体该签名的使用权。比如:
注意,未上架的应用,以应用名申请签名,以应用商店后台开发者管理截图作为资质文件,运营商审核人员不会通过。 如果该应用有同名的小程序、公众号、网站,或者为应用名称注册了商标,可以提交相应的资质文件申请签名。 否则,可以改用公司名或简称作为签名。
短信签名缺失、或没有默认签名、或未通过审核且无其他可用签名,都将导致短信无法发送。
签名规范
应用A
为 3 个字符;【】
;短信模板
开发者可以使用短信模板来自定义短信的内容。
创建模板
要创建短信模板,先进入控制台,选择一个应用,再选择 短信 > 签名与模版。选择需要的模板类型:
如果模板类型选择了 通知类 或者 验证类,但短信内容涉及到营销内容,则无法通过审核。要发送营销类短信请阅读 营销短信。
模板审核
为了确保短信内容的合法性及投递成功率,短信签名、短信模板需要经过 运营商人工审核 通过后,开发者才能在接口中调用该模板。根据我们的经验,短信模板、非营销类短信签名通常需要 1 个工作日,营销类签名审核时间较长,一般需要 2 – 5 个工作日。 如果提交签名、模板后长时间处于「审核中」状态,请提交工单或通过邮件(leancloud-support@xd.com)联系我们处理。
模板规范
验证码类模板,要求如下:
通知类模板,要求如下:
营销类模板,要求如下:
模板变量
模板可以使用自定义变量,在调用模板时以参数形式传入。模板语法遵循 Handlebars 规范。
自定义变量的值不允许包含实心括号
【】
。在模板中还可以使用系统预留变量,在短信发送时,它们会被自动填充,开发者 无法 对其重新赋值:
欢迎注册
{{{name}}}
应用!请使用验证码{{{code}}}
来完成注册。该验证码将在{{{ttl}}}
分钟后失效,请尽快使用。name
:应用名称code
:验证码(通知类和营销类不会包含)ttl
:过期时间(默认为 10 分钟,最长可设置 30 分钟)sign
:短信签名template
:模板名称模板中的链接
短信中的 URL 不允许 全部 设置为变量,这样是为了确保安全,防止病毒以及不良信息的传播。错误范例如下:
尊敬的会员您好,您的订单(订单号
{{{orderId}}}
)已确认支付。5周年庆新品降价!大牌奢品上演底价争霸,低至2折!BV低至888元!阿玛尼低至199元!都彭长款钱包仅售499元!杜嘉班纳休闲鞋仅售1399元!周年庆家居专场千元封顶现已开启!{{{download_link}}}
客服电话400-881-6609 回复TD退订以上通知内容包含了像「打折」、「降价」、「仅售」这类营销推广的敏感词语,容易导致审批无法通过,因此请谨慎使用或改用 营销类短信。
但是 URL 中可以包含变量,比如:
亲,您的宝贝已上路,快递信息可以通过以下链接查询:http://www.sf-express.com/cn/#search/
{{{bill_number}}}
模板申请范例
通知类模板
【正确范例】
恭喜您获得关注广州体彩微信送“排列三”的活动彩票,您的号码是第
{{{phase}}}
期的:{{{num}}}
。开奖时间为{{{date}}}
,请关注公众号—开奖信息查询中奖状态。〖错误范例〗
您好,本条短信来自“XX旅游”~恭喜幸运的您,在本次“北海道机票”抽奖活动中,获得二等奖——定制星巴克杯! 请您关注我们的微信公众号(XX旅游:xx_app),回复“中奖名单”即可查看详细中奖名单及领取须知!后续还会有更多活动惊喜,期待您的参与~官方网站:xxsite.cn
错误点在于不可以在 通知类短信 模板中发送带有抽奖中奖信息等营销信息的内容。解决方案是 在创建模板的时候选择 营销类短信。
另外,有一些行业相关的敏感词语是不允许发送的,错误范例如下:
业主还在苦苦等待你的反馈,你认领的房源已超过1小时没有填写核实结果,请尽快登录XX客户端,在“业主--待处理”列表中进行填写。【XX网】
无论是通知类还是营销类短信,凡包含「房源」、「借贷」这类敏感词的短信都被禁止发送。
营销类模板
【正确范例 · 销售类】
X牌新款春装已经上市,明星夫妻同款你值得拥有!详情请咨询当地X牌门市店,或者直接登录 www.xxxx.com 查询门市店,或者拨打 010-00000000,凭短信可享 9 折优惠。
【正确范例 · 推广类】
还在找寻同桌的 TA 吗?还在烦恼过年回家联系不上老同学吗?iOS 用户在 App Store 搜索:找同学,下载最新版的找同学,让同学聚会重温往日时光!
注意:应用的下载链接必须是明文,不可设置为参数。
使用模板
假设提交的短信模板的类型为「通知类」,内容如下:
尊敬的的用户,您的订单号:
{{{order_id}}}
正在派送,请保持手机畅通,我们的快递员随时可能与您联系,感谢您的订阅。并且模板名称为
Order_Notice
,并且为已经拥有了一个审核通过的签名叫做「天天商城」,签名的名称叫做sign_BuyBuyBuy
,当模板通过审批后就可以调用如下代码发送这条通知类的短信:用户收到的内容如下:
【天天商城】尊敬的用户,您的订单号:7623432424540 正在派送,请保持手机畅通,我们的快递员随时可能与您联系,感谢您的订阅。
短信轰炸与图形验证码
短信在提供便利性和实用性的同时,也会受到攻击而被滥用,产生经济损失,甚至影响到品牌形象。「短信轰炸」就是最常见的一种攻击手段——恶意攻击者使用软件来自动收集一些不需要认证就能发送短信验证码的网站,利用这些网站的漏洞,攻击者能以程序化方式批量地向手机号重复发送短信,这样造成的后果就是:
因此开发者需要重视对此类攻击的防范。目前,图形验证码(又称 CAPTCHA)是防范短信轰炸最有力的手段。比如,我们在一些网站注册的时候,经常需要填写以下图片的信息:
网站必须在用户进行「免费获取验证码」操作前,要求用户先输入图形验证码来确认操作真实有效,服务器端再请求 LeanCloud 云端发送动态短信到用户手机上,这样才可以有效防范恶意攻击者。
图形验证码的基本工作流程如下:
开通图形验证码服务
要针对短信验证码启用图形验证码,开发者需要进入 控制台 > 设置 > 安全中心,打开 图形验证码服务。
如果希望强制所有的短信接口都必须通过图形验证码验证才能发送,则进入 控制台 > 短信 > 设置,选中 强制短信验证服务使用图形验证码。注意:这样一来,所有主动调用发送短信的接口都会强制进行图形验证码验证,否则会直接返回调用错误。
LeanCloud 提供的图形验证码服务仅提供基本的防范,如有必要,可以自行接入功能更强大的第三方验证码服务。
前端接入示例
我们以 HTML + JavaScript 实现一个很小的功能页面,演示图形验证码接入的流程。
组件初始化
初始化图形验证码组件:
配置参数说明
AV.Captcha.request()
在生成AV.Captcha
实例的时候,可以指定如下参数:width
number
85
height
number
30
例如可以这样初始化一个展示高度为 30px、宽度为 80px 的
captcha
实例:captcha.bind()
方法可以将captcha
实例与界面元素绑定起来,它支持如下参数:textInput
string
或HTMLInputElement
id
。image
string
或HTMLImageElement
id
。verifyButton
string
或HTMLElement
id
。完整示例
以下为上述 demo 的完整代码:
图形验证码 API
获取图形验证码
校验图形验证码
获取图形验证码之后,将图形验证码的图像显示在客户端(iOS 和 Android 或者其他平台可以调用基础的图像控件展示该图片),等到用户输入完成之后,继续调用下一步的接口校验用户输入的是否合法。
使用
validate_token
发送短信如果校验成功,拿到返回的
validate_token
,继续调用发送短信的接口:国际短信
向国外用户发送短信,只需要在手机号码前加上正确的国际区号即可,如美国和加拿大为
+1
,当然前提是已在短信设置中选中了 开启国际短信服务。中国区号为+86
,但可以省略。无区号的手机号码会默认使用中国区号。请参阅官网的价格页面以了解 LeanCloud 支持的国家和地区。
注意,国际版应用主要面向国际用户,短信模板无需人工审核(在控制台创建后自动通过)。 也因为没有经过审核,通过国际版应用向国内手机号(
+86
)发送的短信,会有很大几率被运营商拦截,到达率会很低。 建议另外使用国内版的应用往国内手机号发送短信。与 LeanCloud 账户系统集成
LeanCloud 提供了内建的 账户系统 来帮助开发者快速完成用户的注册、登录、重置密码等功能,同时为了方便使用,我们也集成了账户系统手机号码相关的短信功能,譬如账户注册时自动验证手机号、手机号码登录和重置密码等等。
我们可以在「控制台 > 内建账户 > 设置」查看相关选项:
✓从客户端注册或更新手机号时,向注册手机号码发送验证短信
AVUser
相关接口时,如果传入了手机号,系统则会自动发送验证短信。不过,即使开启这一选项,开发者仍然需要手动调用验证接口(/verifyMobilePhone/<code>
),这样_User
表中的mobilePhoneVerified
值才会被置为true
。因此我们不建议勾选这一选项,如果需要在绑定或更新手机号时验证手机号,可以使用requestChangePhoneNumber
接口。AVUser
相关接口不会发送短信。✓未验证手机号码的用户,禁止登录
AVUser
不能使用「手机号 + 密码」以及「手机号 + 短信验证码」的方式登录,但是用户名搭配密码的登录方式不会失败。✓未验证手机号码的用户,允许以短信重置密码
AVUser
通过短信验证码实现重置密码的功能。AVUser
必须在使用短信重置密码之前,先行验证手机号,也就是mobilePhoneVerified
字段必须是true
的前提下,才能使用短信重置密码。✓已验证手机号码的用户,允许以短信验证码登录
AVUser
可以使用手机号搭配短信验证码的方式登录。AVUser
不能使用手机号搭配短信验证码的方式登录。《数据存储开发指南》中详细介绍了如何通过手机号 注册 和 登录,以及如何 验证已有用户的手机号。
未收到注册验证短信
一般来说,用户收到的注册验证短信内容为:
【Signature】欢迎使用「应用名称」服务,您的验证码是 123456,请输入完成验证。
其中「Signature」为短信签名,必须遵循 短信签名规范 中的长度及其他要求,否则会被短信供应商拒绝发送。
常见问题
详情请参照 短信收发常见问题一览。
短信计费
如果一个短信模板字数超过 70 个字(包括签名的字数),那么该短信在发送时会被运营商按多条来收取费用,但接收者收到的仍是一条完整的短信。
只有「调用失败」不收费,「投递失败」也要收费。每条短信的收费标准请参考官网价格方案。
短信购买
短信发送采取实时扣费。如果当前账户没有足够的余额,短信将无法发送。充值请进入 开发者账户 > 财务 > 概览,点击 余额充值。
同时我们建议设定好余额告警,以便在第一时间收到短信或邮件获知余额不足。