一般现在平台的用户在注册时都是使用手机号注册,所以就需要用到手机介绍短信验证码实现注册,在这里我调用的是榛子云短信平台第三方提供的短信服务发送验证码。
短信验证码实现流程
1、构造手机验证码,生成一个6位的随机数字串;
2、使用接口向短信平台发送手机号和验证码,然后短信平台再把验证码发送到制定手机号上
3、将手机号验证码、操作时间存入map中,作为后面验证使用;
4、接收用户填写的验证码、手机号及其他注册数据;
5、对比提交的验证码与map中的验证码是否一致,同时判断提交动作是否在有效期内;
6、验证码正确且在有效期内,请求通过,处理相应的业务。
前端jsp
<div class="register-content">
<h1><span>用户注册</span><em class="fr">已有账户,<a href="${ctx}/login">立即登录</a></em></h1>
<div class="register-div">
<form action="login.html" id="registForm" method="post">
<label for=""><i>*</i>手机号(登录账号):</label>
<input type="text" class="register-div-tel" id="phone" name="mobile">
<button type="button" class="send-code" onclick="settime(this)">发送验证码</button>
<br>
<label for=""><i>*</i>填写验证码:</label>
<input type="text" id="verificationCode" name="verificationCode">
<br>
<label for=""><i>*</i>设置登录密码:</label>
<input autocomplete="new-password" type="password" id="newPassword" name="password">
<br>
<label for=""><i>*</i>重复登录密码:</label>
<input autocomplete="new-password" type="password" id="againPassword" name="againPassword">
<br>
<label for="">填写QQ号:</label>
<input type="text" id="qqNumber" name="qqNumber">
<br>
<label for=""><i>*</i>昵称:</label>
<input type="text" id="nickname" name="nickname">
<!-- <span><i>✕</i>请填写信息</span> -->
<p>昵称长度3-15位,支持汉字、数字、字母、下划线.组合。</p>
<br>
<label for="">邀请码:</label>
<input type="text" id="inviteUserCode" name="inviteUserCode">
<p>没有邀请码可不填写</p>
<br>
<!-- <label for="">来源:</label>
<select name="" id="">
<option value=""></option>
</select> -->
<div class="read-notice">
<input type="checkbox" id="checkbox" checked="checked" onclick="terms()">
<em>我已仔细阅读并同意接受<a onclick="window.open('${ctxStaticMc}/htmls/merchantProtocol.html')" style="cursor:pointer;">《用户使用协议》</a></em>
</div>
<button type="button" class="register-submit" id="btn_reg" onclick="regist()">提交</button>
</form>
</div>
</div>
前端ajax请求
$.ajax({
url : "${ctx}/sendPhoneSms",
cache : false,
dataType : "json",
data : {
"mobile" : $("#phone").val(),
"type" : "1"
},
type : 'POST',
success : function(successData){
if (successData.code == 0) {
layer.msg(successData.msg,{icon: 1});
countdown--;
settime(val)
} else {
layer.msg(successData.msg,{icon: 2});
val.removeAttribute("disabled");
countdown=60;
}
},
});
后端代码
@AccessLimit(maxCount=10)//一个ip下面,1分钟最多发送10次验证码。
@RequestMapping(value ="sendPhoneSms",method = RequestMethod.POST)
@ResponseBody
public RestResponse sendPhoneSms(String mobile,String type) {
RestResponse restResponse = new RestResponse();
try {
//String phone=RequestUtil.getString("phone",request);
//Assert.hasText(phone,"手机号不能为空");
Assert.isTrue(mobile != null && mobile.length() == 11, "手机号不规范");
//String type= RequestUtil.getString("type",request);
Assert.hasText(type,"type不能为空,1为注册,2为重置或修改类型");//type :1 注册, 2 重置或修改 类型。
Assert.isTrue("1".equals(type),"");
BusinessUser businessUserDb = businessUserService.findOneByLoginName(mobile);
Assert.isTrue(businessUserDb==null , "系统中存在此手机号用户,请登录");
String res = SMSUtils.sendSms(mobile) +"";
if("0".equalsIgnoreCase(res)){
return new RestResponse("发送成功");
}else{
return new RestResponse(RestErrorCode.SEND_SMS_FAILED, "发送失败");
}
} catch (Exception ex) {
restResponse=ExceptionUtil.dealException(ex);
}
return restResponse;
}
发送短信服务工具类smsutil
package com.hb.internet.common.sms;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import org.springframework.util.Assert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.hb.internet.common.config.Global;
import com.hb.internet.common.security.Digests;
import com.hb.internet.common.utils.RandomUtils;
import com.hb.internet.common.utils.StringUtils;
import com.hb.internet.modules.oa.utils.OaNotifyUtils;
import com.zhenzi.sms.ZhenziSmsClient;
/**
* 短信验证码发送工具。 使用说明:SMSUtils.sendSms(手机号) 发送短信。
**/
public class SMSUtils {
static Logger logger = Logger.getLogger(SMSUtils.class);
static String result = null;
/***
* 短信验证码map信息。
*/
public static LoadingCache<String,String> smsCodeMapCahce=CacheBuilder
.newBuilder()
.expireAfterWrite(15, TimeUnit.MINUTES)//给定时间内没有被读/写访问,则回收。
.build(new CacheLoader<String, String>(){
@Override
public String load(String key) throws Exception {
return "";
}
});
public static final String SMS_SIGN = "【买家秀】";
public static final String CONTENT = "您的验证码:%s,15分钟有效。";
//短信接口异常代码信息。
public static Map<String,String> smsErrorMap = new HashMap<String,String>();
public static void main(String[] args) {
System.out.println(SMSUtils.sendSms("18975893631"));
}
/***
* 初始化发送短信错误。
*/
static{
smsErrorMap.put("0", "发送短信成功");
//smsErrorMap.put("1", "成功");
smsErrorMap.put("-1", "短信帐户非法");
smsErrorMap.put("-2", "短信帐户已禁用");
smsErrorMap.put("-3", "短信存量不足");
smsErrorMap.put("-4", "默认错误");
smsErrorMap.put("-5", "默认错误");
smsErrorMap.put("-6", "默认错误");
}
/***
* 按手机号发送 短信验证码。
***/
public static int sendSms(String mobile){
String verificationCode = RandomUtils.generateConfirmCode(6,0);
logger.info("mobile:"+mobile+",verificationCode:"+verificationCode);
String apiUrl="https://sms_developer.zhenzikj.com";
String appId="104399";
String appSecret="cd6aaba6-e444-4465-9a76-1267aa9e6b10";
ZhenziSmsClient client = new ZhenziSmsClient(apiUrl, appId, appSecret);
Map<String, String> params = new HashMap<String, String>();
String content = String.format(CONTENT,verificationCode);
params.put("message", "买家秀"+content);
params.put("number", mobile);
try {
result = client.send(params);
} catch (Exception e) {
e.printStackTrace();
}
smsCodeMapCahce.put(mobile, verificationCode);//设置到Map内存中去
return sendValidateSms(content,SMS_SIGN,mobile);
}
/***
* 校验 短信验证码。
* @param mobile 手机号
* @param verificationCode 验证码
* @return
* @throws ExecutionException
*/
public static boolean verificationSmsCode(String mobile, String verificationCode) throws ExecutionException {
//#TODO 如果是测试环境。并且验证码为888888 则不需要验证,直接跳过短信验证码验证。
if(Global.isTestMode() && StringUtils.equalsIgnoreCase(verificationCode, "888888")){
return true;
}
Assert.hasText(verificationCode, "验证码不能为空");
Assert.hasText(mobile, "手机号不能为空");
if(StringUtils.equalsIgnoreCase(smsCodeMapCahce.get(mobile),verificationCode)){
//使用完毕后,让缓存中的验证码失效。
SMSUtils.smsCodeMapCahce.invalidate(mobile);
return true;
}else{
return false;
}
}
public static int sendValidateSms(String content,String smsSign,String mobile){
int code =-1;
try {
JSONObject jsonObject = null;
jsonObject = JSON.parseObject(result);
if (jsonObject != null && jsonObject.containsKey("code") && jsonObject.getString("code") != null) {
String codeStr = jsonObject.getString("code");
//1:成功
//-1:短信帐户非法
//-2 短信帐户已禁用
//-3 短信存量不足
//-4 未知错误
if(StringUtils.isNumeric(codeStr)){
code = Integer.parseInt(codeStr);
}
}
} catch (Exception ex) {
logger.error(ex,ex);
code = -6;
//提交短信发送出现异常
//return ("提交短信发送出现异常");
}
if(code !=0){
//发送系统消息给到管理员。
String msg = "buyershow-api模块,发送短信接口出错,错误返回值:"+code+",错误信息:"+ SMSUtils.smsErrorMap.get(code+"");
OaNotifyUtils.sendNotifyToAdmin(msg, msg);
}
return code;
}
private static String get(String url) {
BufferedReader in = null;
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
// 建立实际的连接
connection.connect();
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = in.readLine()) != null) {
sb.append(line);
}
return sb.toString();
} catch (Exception e) {
//LOG.error("Exception occur when send http get request!", e);
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return null;
}
//发送短信,uid,pwd,参数值请向企信通申请, tel:发送的手机号, content:发送的内容
public static String send(String uid, String pwd, String tel, String content) throws IOException {
// 创建StringBuffer对象用来操作字符串
StringBuffer sb = new StringBuffer("http://api.cnsms.cn/?");
// 向StringBuffer追加用户名
sb.append("ac=send&uid="+uid);//在此申请企信通uid,并进行配置用户名
// 向StringBuffer追加密码(密码采用MD5 32位 小写)
sb.append("&encode=utf8");
// 向StringBuffer追加密码(密码采用MD5 32位 小写)
sb.append("&pwd="+Digests.string2MD5(pwd));//在此申请企信通uid,并进行配置密码
// 向StringBuffer追加手机号码
sb.append("&mobile="+tel);
// 向StringBuffer追加消息内容转URL标准码
sb.append("&content="+URLEncoder.encode(content,"utf8"));
// 创建url对象
URL url = new URL(sb.toString());
// 打开url连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置url请求方式 ‘get’ 或者 ‘post’
connection.setRequestMethod("POST");
// 发送
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
// 返回发送结果
String inputline = in.readLine();
return inputline;
}
}