手机验证码缓存的实现
验证码缓存实现
1. 验证码存储
Key: sms:validate:code:{phone}
Value: 验证码数字
过期时间: 默认5分钟(可配置)
2. 发送频率限制
Key: sms:validate:phone:{phone}
Value: 1(占位符)
过期时间: 60秒
核心代码实现
发送验证码
在SmsServiceImpl.sendSms方法中:
// 生成6位随机验证码
Integer code = CrmebUtil.randomCount(111111, 999999);
// 将验证码存入redis,过期时间默认5分钟
redisUtil.set(userService.getValidateCodeRedisKey(phone), code, Long.valueOf(codeExpireStr), TimeUnit.MINUTES);
// 设置发送频率限制,60秒内不能重复发送
redisUtil.set(SmsConstants.SMS_VALIDATE_PHONE_NUM + phone, 1, 60L);
其中
userService.getValidateCodeRedisKey(phone)方法返回完整的key
public String getValidateCodeRedisKey(String phone) {
return SmsConstants.SMS_VALIDATE_PHONE + phone;
}
验证验证码
UserCenterServiceImpl.checkValidateCode方法中:
private void checkValidateCode(String phone, String code) {
Object validateCode = redisUtil.get(SmsConstants.SMS_VALIDATE_PHONE + phone);
if (validateCode == null) {
throw new CrmebException("验证码已过期");
}
if (!validateCode.toString().equals(code)) {
throw new CrmebException("验证码错误");
}
// 验证成功后删除验证码
redisUtil.delete(SmsConstants.SMS_VALIDATE_PHONE + phone);
}
频率限制检查
在发送验证码前会检查发送频率:
if (redisUtil.exists(SmsConstants.SMS_VALIDATE_PHONE_NUM + phone)) {
throw new CrmebException("您的短信发送过于频繁,请稍后再试");
}
这种设计确保了:
验证码在一定时间内有效(默认5分钟)
防止短信轰炸(60秒内只能发送一次)
验证码一次性使用(验证成功后立即删除)
防重复发送短信验证码机制
在CRMEB系统中,通过Redis实现了一个简单的频率限制机制,防止用户在60秒内重复发送短信验证码。
实现原理
这个机制的核心在于使用Redis的过期时间(TTL)特性:
// 设置发送频率限制,60秒内不能重复发送
redisUtil.set(SmsConstants.SMS_VALIDATE_PHONE_NUM + phone, 1, 60L);
这行代码的作用是:
以键 sms:validate:phone:{phone} 在Redis中存储一个值为1的数据
设置该键的过期时间为60秒
检查机制
在发送短信验证码前,系统会检查该键是否存在:
if (redisUtil.exists(SmsConstants.SMS_VALIDATE_PHONE_NUM + phone)) {
throw new CrmebException("您的短信发送过于频繁,请稍后再试");
}
工作流程
用户请求发送验证码
系统检查Redis中是否存在 sms:validate:phone:{phone} 键
如果存在,说明60秒内已发送过验证码,抛出异常
如果不存在,继续执行发送验证码流程
发送验证码成功后,设置 sms:validate:phone:{phone} 键,有效期60秒
为什么能实现60秒限制
Redis的过期机制会自动在60秒后删除这个键,所以:
在60秒内,键存在,系统拒绝发送新的验证码
60秒后,键自动过期并被删除,下次请求时检查发现键不存在,允许发送验证码
这是一种简单而有效的方式,利用了Redis的自动过期特性来实现时间窗口内的频率控制。