在写注册的时候想使用手机号进行验证,用来保证用户的安全性操作,因为以前使用的是邮箱验证,太麻烦了。所以在网上找到了一个比较好的第三方提供短信送达服务,有的还需要企业用户认证,这里我选择的是网易云的短信服务。试了下,速度还不错,基本三秒左右就可以收到短信。这是网址https://www.163yun.com/product/sms,点击免费试用就可以了。
先说下整个模块的步骤:
- 前端出发获取验证码,同时开始倒计时
- 后台通过代理平台发送验证码信息
- 用户提交表单后,在后台进行验证码的验证
项目的整个文档结构如下图:可以在文章最后的连接中下载项目文件:
下面详细介绍具体功能的实现
一、前台页面
首先本文的例子是通过springmvc实现的,所以要先把基本的配置搭好,然后先是写好前端界面。如下图所示(界面有点简单,将就着看,重在实现)
代码如下:
<%@ page contentType="text/html;charset=UTF-8"%>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="../static/js/register.js"></script>
</head>
<body>
<div>
<form action="validation" method="post">
<div align="left">
手机号:<input id="phone" name="phone" class="phone" type="number">
<br><hr>
验证码:<input id="verification" name="verification" type="number">
<input type="button" value="获取验证码" name="yzm" class="yzm" disabled="disabled">
<br><br>
<input type="submit" id="submit" value="提交">
</div>
</form>
</div>
</body>
</html>
还有我们的js代码,这里使用的jQuery,所以jsp页面头要引入jQuery。js已经写了注释,有不明白的可以搜索下
$(document).ready(function(){
var ordertime=20 //设置再次发送验证码等待时间
var timeleft=ordertime
var btn=$(".yzm")
var phone=$(".phone")
var tel
var reg = /^1[0-9]{10}$/; //电话号码的正则匹配式
phone.keyup(function() {
if (reg.test(phone.val())) {
tel = phone.val()
btn.removeAttr("disabled") //当号码符合规则后发送验证码按钮可点击
} else {
btn.attr("disabled", true)
}
})
//计时函数
function timeCount() {
timeleft -= 1
if (timeleft > 0) {
btn.val(timeleft + " 秒后重发");
setTimeout(timeCount, 1000)
} else {
btn.val("重新发送");
timeleft = ordertime //重置等待时间
btn.removeAttr("disabled");
}
}
//事件处理函数
btn.on("click", function() {
$(this).attr("disabled", true); //防止多次点击
timeCount(this);
var paras = "o_tel="+tel;
//此处为向后台的请求,获取验证码
$.post('http://localhost:8080/Phone_verification/login/sendCode?'+paras,function(data) {
if(data!=null&&typeof(data)!="undefined"){
var msg = data.msg; //返回值为json格式
if(msg!=null&&typeof(msg)!="undefined"&&msg=="SUCCESS"){
}else{
alert("短信验证码发送失败!请重新获取。");
}
}else{
alert("短信验证码发送失败!请重新获取。");
}
},"json");
});
});
二、后台处理
后台接收到js的请求后调用相应的controller ,sendCode方法,方法中实现了对前台数据中的手机号,然后通过调用网易云实例中给代码,给平台发送HTTP请求,接入短信接口。
其中重要的有四个参数需要根据自己网易云控制台中的信息进行修改,分别是
- AppKey:开发者平台分配的appkey
- Nonce:这个我已经通过controller生成了随机数
- CurTime:当前UTC时间戳,从1970年1月1日0点0 分0 秒开始到现在的秒数(String)
- CheckSum:SHA1(AppSecret + Nonce + CurTime),三个参数拼接的字符串,进行SHA1哈希计算,转化成16进制字符(String,小写)
其中Appkey,Appsecret获取步骤:
- 成为云信开发者
- 登录云信管理后台(http://app.netease.im/login)
- 创建应用
- 打开App Key管理
下面是sendCode()方法的具体代码:
@RequestMapping(value="/sendCode",method={RequestMethod.POST,RequestMethod.GET})
public String sendCode(HttpServletRequest request,HttpServletResponse response) throws Exception{
String ret="";
String o_tel = request.getParameter("o_tel");//获取前端传送过来的电话号码
if(o_tel!=null&&o_tel!=""){
int Random = (int) ((Math.random()*9+1)*100000);//随机生成的6位数(验证码)
//调用封装的工具类SendCode 返回验证码
SendCode s = new SendCode();
verification = s.send(o_tel, Random);
if(verification != null){
ret = "{\"msg\":\"SUCCESS\"}";
}else{
ret = "{\"msg\":\"ERROR\"}";
}
}else{
ret = "{\"msg\":\"ERROR\"}";
}
response.setContentType("application/json;charset=UTF-8");
PrintWriter writer = null;
try {
writer = response.getWriter();
} catch (IOException e) {
e.printStackTrace();
}
writer.write(ret);//推送回前端
return null;
}
其中SendCode 类为:调用的getCheckSum(),我这里直接使用的是网易云实例文档中计算CheckSum的java代码。
package tool;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
/**
* 发送验证码
* @author liuxuanlin
*
*/
public class SendCode {
//发送验证码的请求路径URL
private static final String
SERVER_URL="https://api.netease.im/sms/sendcode.action";
//网易云信分配的账号,请替换你在管理后台应用下申请的Appkey
private static final String
APP_KEY="**********************";
//网易云信分配的密钥,请替换你在管理后台应用下申请的appSecret
private static final String APP_SECRET="**********";
//短信模板ID
private static final String TEMPLATEID="******";
//验证码长度,范围4~10,默认为4
private static final String CODELEN="6";
public String send(String MOBILE,int Random) throws Exception {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(SERVER_URL);
String curTime = String.valueOf((new Date()).getTime() / 1000L);
/*
* 参考计算CheckSum的java代码,在上述文档的参数列表中,有CheckSum的计算文档示例
*/
String NONCE = String.valueOf(Random);
String checkSum = CheckSumBuilder.getCheckSum(APP_SECRET, NONCE, curTime);
// 设置请求的header
httpPost.addHeader("AppKey", APP_KEY);
httpPost.addHeader("Nonce", NONCE);
httpPost.addHeader("CurTime", curTime);
httpPost.addHeader("CheckSum", checkSum);
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
// 设置请求的的参数,requestBody参数
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("templateid", TEMPLATEID));
nvps.add(new BasicNameValuePair("mobile", MOBILE));
nvps.add(new BasicNameValuePair("codeLen", CODELEN));
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
// 执行请求
HttpResponse response = httpClient.execute(httpPost);
/*
* 1.打印执行结果,打印结果一般会200、315、403、404、413、414、500
* 2.具体的code有问题的可以参考官网的Code状态表
*/
String result = EntityUtils.toString(response.getEntity(), "utf-8");
String verification = result.split("\"")[9];
System.out.println("验证码发送成功!");
return verification;
}
}
这个是跳转到主页的controller:
@RequestMapping(value="/index")
public String send(){
return "index";
}
最后就是对提交上的form表单中的验证码进行验证,这里我讲form表单中的数据封装到一个POJO中,然后对比验证码进行注册是否成功。
@RequestMapping(value="/validation")
//将前台界面form表单中的数据放入Phone类中
//当获取不是POJO里面的参数的时候使用@RequestParam获取。
public String login(@ModelAttribute("form") Phone phone){
/*
* 验证数据
System.out.println("验证码为:"+verification);
System.out.println(phone.getPhone()+"------"+phone.getVerification());
*/
//对验证码进行判断后跳转到相应的界面中
if(phone.getVerification().equals(verification)){
return "success";
}
else{
return "failure";
}
}
以上就是注册时对手机发送短信的具体验证的实现,核心内容上面都已经介绍的差不多了,代码有些粗糙,大家可以再修改下,如果是配置上出现错误可以看我上传到CSDN的项目文件对比下。
最后,如果文中如果出现了什么不足之处,还望指点与纠正。