在实际项目开发中,几乎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(); } }