在实际项目开发中,几乎90%都需要实现手机验证码登录场景,10分钟只能发送3次验证码,且验证码发送成功后只能验证一次有效。看似很常见很简单的功能,但是需要做到稳定、用户体验好,还是需要两把刷子的。下面将介绍通过使用redis分布式锁来实现验证码只发送一次的功能:
1.生成验证码
一般生成6位数字组合的验证码,验证码的唯一性要求不高,确保大概率不重复即可。
//生成6位随机数
public static String generate6Random() {
Integer ran = (int)((Math.random()*9+1)*100000);
return ran.toString();
}
2.编写发送规则
根据实际项目需求,一般验证码发送规则有要求,下面以“10分钟内发送3条短信”为例:
String smsLimitFlag="-1";
try {
Object smsLimitFlagObj = redisService.get("smsLimitFlag:"
+ mobile);
Object smsLimitFlagTimeObj = redisService.get("smsLimitFlagTime:"
+ mobile);
if (smsLimitFlagTimeObj != null) {
String smsLimitFlagObjStr=(String)smsLimitFlagObj;
if(smsLimitFlagObjStr!=null&&smsLimitFlagObjStr.length()>0&&Integer.valueOf(smsLimitFlagObjStr).intValue()>=3){
smsLimitFlag = "1";
}
}
} catch (Exception e) {
e.printStackTrace();
}
if("1".equals(smsLimitFlag)){
return ResultInfoUtils.businessError(ResultStatusCode.DELETE_USER_MISS_ERROR.getReturnCode(),
"验证码10分钟内只能获取3条,请稍后再试", mobile);
}
3.建立redis存储机制
短信发送成功后将发送的时间和手机号存储到redis中。
try {
Object smsLimitFlagObj = redisService.get("smsLimitFlag:"
+ mobile);
Object smsLimitFlagTimeObj = redisService.get("smsLimitFlagTime:"
+ mobile);
if (smsLimitFlagTimeObj == null) {
redisService.set("smsLimitFlagTime:" + mobile, mobile, 10*60L);
redisService.set("smsLimitFlag:" + mobile, "1", 10*60L);
}else{
if (smsLimitFlagObj != null) {
String smsLimitFlagObjStr=(String)smsLimitFlagObj;
redisService.set("smsLimitFlag:" + mobile, ""+(Integer.valueOf(smsLimitFlagObjStr).intValue()+1), 10*60L);
}else{
redisService.set("smsLimitFlag:" + mobile, "1", 10*60L);
}
}
} catch (Exception e) {
e.printStackTrace();
}
4.采用redis分布式锁,防止短信重复发送
public void sendSms(String mobile,String smsContent) {
//加分布式锁
RLock lock = redisson.getLock("sendSms" + mobile);
try {
lock.lock();
//短信发送逻辑
} finally {
//解锁
lock.unlock();
}
}