发送短信验证码
- 1.获取AppKey和Master Secret
- 2.设置短信模板和短信签名
- 3.开始服务端接口的实现
1.获取AppKey和Master Secret
首先应有一个极光推送官网的账号,然后添加你的应用,也就是为了拿到下文中使用的AppKey和Master Secret这两个参数,便于下文的使用。添加应用可以参考官网的文档,这里主要记录一下自己调用短信验证码接口遇到的坑。
2.设置短信模板和短信签名
在拿到第一步的两个参数之后,然后进行验证码短信信息的设置,鼠标放在屏幕的最左侧,可以看到极光短信。
极光短信页面,可以看到数据概览,这里可以显示出账号的剩余短信条数,也就是第三个图标行业余量
刚开始还以为第一个短信余量就是验证码的短信呢,后来才发现不是的,行业余量里面也包含了短信验证业务。点击左侧的签名管理,进行签名的设置,之前极光推送可以不用设置签名,默认使用极光推送的签名,也就是短信验证码信息的最签名中括号里面的内容,即为签名。
例如:【天眼查】你好, 你的验证码是:2047,有效时间3分钟
,这里天眼查即为短信的签名。
可以看到我这里面已经有一个签名了,如果没有签名,点击右上角的创建签名,可以设置自己的短信签名。这个是必须要有的,因为现在极光推送不在提供默认的签名了,需要自己设置,创建的第一个签名即为默认签名。
然后是短信模板的设置,具体的填写要求,可以看到页面的提示信息,这点还是很详细的。
3.开始服务端接口的实现
这里先贴一下极光的文档,要是你看的云里雾里的话,再往下看,可能会对你有帮助,如果你按照文档直接写出来了,就不用浪费时间看这篇博客了。
个人建议还是使用极光推送的SDK,这样比较省事,避免不必要的麻烦,我刚开始是看着文档自己写的,结果各种坑,使用SDK一时爽,一直使用一直爽。
首先是导入依赖:https://docs.jiguang.cn/jsms/server/sdk/java_sdk/ 具体看下这个文档,其中 LATEST_VERSION 的值可在 release 页面 获取。
目前我用的版本是
<dependency>
<groupId>cn.jpush.api</groupId>
<artifactId>jsms-client</artifactId>
<version>1.2.9</version>
</dependency>
直接复制上面的文档里的依赖也可以,但是如果项目中已经导入了log4j的jar包,再导入slf4j包时,控制台会报错,这两者留一个即可。
这里有必要贴一下极光推送github上的demo,刚开始还真没看明白怎么回事,就一直按照文档闷头写,然后各种问题。。。。。
https://github.com/jpush/jsms-api-java-client/blob/master/example/main/java/cn/jsms/api/JSMSExample.java#L33
极光推送提供了两种方式验证码的方式,一种是直接由极光平台生成随机验证码,服务端只需传手机号即可,然后调用短信验证码验证接口,验证用户输入的验证码是否正确,这种方式不需要服务端生成随机验证码,并且验证码的有效性也是极光平台来完成的,服务端只需要调用相关的接口即可。
另一种是设置短信模板,服务端自己生成随机验证码,极光平台负责给用户发送短信验证码短信,验证码的正确性需要服务端自己验证。
这里使用第二种方式,也就是使用短信模板,服务端自己验证验证码的有效性和正确性。
使用模板发送单条短信:使用这个方法 testSendTemplateSMS()
public static void testSendTemplateSMS() {
SMSClient client = new SMSClient(masterSecret, appkey);
SMSPayload payload = SMSPayload.newBuilder()
.setMobileNumber("13800138000")
.setTempId(1)
.addTempPara("code", "666666")
.build();
try {
SendSMSResult res = client.sendTemplateSMS(payload);
LOG.info(res.toString());
} catch (APIRequestException e) {
LOG.error("Error response from JPush server. Should review and fix it. ", e);
LOG.info("HTTP Status: " + e.getStatus());
LOG.info("Error Message: " + e.getMessage());
} catch (APIConnectionException e) {
LOG.error("Connection error. Should retry later. ", e);
}
}
此方法返回结果是 {"msg_id":"773945179045"}
这里没有设置签名,默认使用了上面我们自己设置的签名,如果账号里面有多个签名,可以在SMSPayload.newBuilder()后面使用.setSignId(signId)
使用指定的签名。
使用模板进行群发短信:使用testSendBatchTemplateSMS()方法
public static void testSendBatchTemplateSMS() {
SMSClient client = new SMSClient(masterSecret, appkey);
List<RecipientPayload> list = new ArrayList<RecipientPayload>();
RecipientPayload recipientPayload1 = new RecipientPayload.Builder()
.setMobile("13800138000")
.addTempPara("code", "638938")
.build();
RecipientPayload recipientPayload2 = new RecipientPayload.Builder()
.setMobile("13800138000")
.addTempPara("code", "829302")
.build();
list.add(recipientPayload1);
list.add(recipientPayload2);
RecipientPayload[] recipientPayloads = new RecipientPayload[list.size()];
BatchSMSPayload smsPayload = BatchSMSPayload.newBuilder()
.setTempId(1)
.setRecipients(list.toArray(recipientPayloads))
.build();
try {
BatchSMSResult result = client.sendBatchTemplateSMS(smsPayload);
LOG.info("Got result: " + result);
} catch (APIConnectionException e) {
LOG.error("Connection error. Should retry later. ", e);
} catch (APIRequestException e) {
LOG.error("Error response from JPush server. Should review and fix it. ", e);
LOG.info("HTTP Status: " + e.getStatus());
LOG.info("Error Message: " + e.getMessage());
}
}
发送多条短信时,返回结果为 {"success_count":1,"failure_count":0}
如果使用第一种方式,使用极光平台生成随机验证码和验证验证码有效性的话,使用方法:
public static void testSendSMSCode() {
SMSClient client = new SMSClient(masterSecret, appkey);
SMSPayload payload = SMSPayload.newBuilder()
.setMobileNumber("13800138000")
.setTempId(1)
.build();
try {
SendSMSResult res = client.sendSMSCode(payload);
System.out.println(res.toString());
LOG.info(res.toString());
} catch (APIConnectionException e) {
LOG.error("Connection error. Should retry later. ", e);
} catch (APIRequestException e) {
LOG.error("Error response from JPush server. Should review and fix it. ", e);
LOG.info("HTTP Status: " + e.getStatus());
LOG.info("Error Message: " + e.getMessage());
}
}
或者这个:
public static void testSendSMSWithIHttpClient() {
SMSClient client = new SMSClient(masterSecret, appkey);
String authCode = ServiceHelper.getBasicAuthorization(appkey, masterSecret);
ApacheHttpClient httpClient = new ApacheHttpClient(authCode, null, ClientConfig.getInstance());
// NettyHttpClient httpClient = new NettyHttpClient(authCode, null, ClientConfig.getInstance());
// ApacheHttpClient httpClient = new ApacheHttpClient(authCode, null, ClientConfig.getInstance());
// 可以切换 HttpClient,默认使用的是 NativeHttpClient
client.setHttpClient(httpClient);
// 如果使用 NettyHttpClient,发送完请求后要调用 close 方法
// client.close();
SMSPayload payload = SMSPayload.newBuilder()
.setMobileNumber("13800138000")
.setTempId(1)
.build();
try {
SendSMSResult res = client.sendSMSCode(payload);
System.out.println(res.toString());
LOG.info(res.toString());
} catch (APIConnectionException e) {
LOG.error("Connection error. Should retry later. ", e);
} catch (APIRequestException e) {
LOG.error("Error response from JPush server. Should review and fix it. ", e);
LOG.info("HTTP Status: " + e.getStatus());
LOG.info("Error Message: " + e.getMessage());
}
}
返回的结果都是:{“msg_id”:“773945179045”},其中的 msg_id
就是我们接下来调用极光平台验证短信验证码正确性和有效性要用到的。
验证验证码有效性的方法:
public static void checkSms(String msgId, String code) {
SMSClient client = new SMSClient(masterSecret, appkey);
try {
ValidSMSResult res = client.sendValidSMSCode(msgId,code);
System.out.println(res.toString());
} catch (APIConnectionException e) {
e.printStackTrace();
} catch (APIRequestException e) {
e.printStackTrace();
}
}
返回结果:{ "is_valid": true}
或者{"is_valid":false,"error":{"code":50026,"message":"wrong msg_id"}}
至此,短信验证码功能就算完成了。
下面记录一下我遇到的坑:
刚开始是这个错误:
- Request is forbidden! Maybe your appkey is listed in blacklist or your params is invalid.
我还以为是appkey被拉入黑名单了呢,结果在极光推送社区问了技术人员之后,发现是自己没有设置签名,而极光推送从新版本中就不在提供默认的签名了。 - {“error”:{“code”:50051,“message”:“signatures not exist”}}
这个问题可能是因为我用的那个appkey的问题,公司账号下面有三个应用,我换了一个appkey之后就正常了。 - 如果使用api文档自己写,直接使用curl访问短信验证码接口的话,需要注意在生成head里的
Authorization
参数时,需要注意,参数值里面包含 Basic 和 空格
,这个如果没有的话,验证也是不通过的。 - 还有个问题就是我使用base64对参数进行加密的时候,我生成的参数和文档里面的参数不一致,我也是很纳闷。
文档里面是这种结果
而我使用的是org.apache.commons.codec.binary.Base64.Base64()这个工具类的encodeToString方法,我生成的结果是这种:NTQ0ZjI5MDY1YWZmZTA2MDIyMjdmMzk1OjIzYTM5NGM4MWQyMTg0NDA4YWE5ODhkNA==,如果哪位大佬知道的话,指点一下也是很好的哇。