思路:key为用户邮箱,value为时间戳,当发送验证码的请求进来先检查是否存在这个key然后将时间戳与当前时间戳比较如果小于验证码发送的时间(比如设置了30s内只能发送一次)则返回"您的操作过于频繁"的提示,否则将key-value设置一定的过期时间存到Redis当中,返回验证码
代码:
@OpLog(title = "邮箱验证码", businessType = "发送")
@GetMapping(value = "/send-security-code", produces = "application/json;charset=UTF-8")
public Result<String> sendSecurityCode(@NotBlank(message = "邮箱不能为空")
@Size(min = 1, max = 50, message = "邮箱长度错误")
@Pattern(regexp = CloudDiskConstantConfiguration.REGULAR_VERIFICATION_EMAIL, message = "邮箱格式错误") String email,
@RequestParam(name = "exist", required = false, defaultValue = "false") Boolean exist,
HttpServletRequest request, HttpServletResponse response) throws IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=UTF-8");
// 如果exist值为true,则需要校验当前邮箱是否存在
if (exist) {
Assert.notNull(diskUserService.getDiskUserToModel("userEmail", email), "该账户不存在,请重新输入");
}
// 根据邮箱地址尝试获取之前的缓存数据
String cacheData = redisTemplate.opsForValue().get(email);
if (StrUtil.isNotBlank(cacheData)) {
// 缓存的时间戳
long timestamp = JSONObject.parseObject(cacheData).getLong("timestamp");
// 时间戳 > 当前的时间戳
if (timestamp >= System.currentTimeMillis()) {
return Result.fail("您的操作过于频繁");
}
}
// 生成4位数随机安全码
String securityCode = RandomUtil.randomStringUpper(4);
// 邮件发送的标题
String subject = StrUtil.format("验证码:{}", securityCode);
// 邮件发送的内容
String content = String.format(CloudDiskConstantConfiguration.MAIL_TEMPLATE_CONTENT, StrUtil.format("您的验证码为: {}<br/>5 分钟内有效。", securityCode));
// 配置邮件发送
MailUtil.send(email, subject, content, true);
// 将结果存入缓存 构建缓存数据
JSONObject jsonObject = new JSONObject();
jsonObject.put("securityCode", securityCode);
// 获取当前时间偏移1分钟后的时间戳
jsonObject.put("timestamp", DateUtil.offset(new Date(), DateField.MINUTE, 1).getTime());
//这个api设置了过期时间,最后一个参数是时间单位
redisTemplate.opsForValue().set(email, jsonObject.toJSONString(), CACHE_TIME, TimeUnit.MILLISECONDS);
return Result.ok("验证码已发送");
}
//校验验证码:
@OpLog(title = "邮箱验证码", businessType = "校验")
@GetMapping(value = "/verify-security-code", produces = "application/json;charset=UTF-8")
public Result<Boolean> verifySecurityCode(@NotBlank(message = "请输入邮箱")
@Size(min = 1, max = 50, message = "邮箱长度错误")
@Pattern(regexp = CloudDiskConstantConfiguration.REGULAR_VERIFICATION_EMAIL, message = "邮箱格式错误") String email,
@NotBlank(message = "请输入验证码")
@Size(min = 1, max = 50, message = "验证码长度错误") String code,
HttpServletRequest request, HttpServletResponse response) throws IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=UTF-8");
// 获取邮箱验证码校验结果
String validationResult = securityCodeValidation(email, code);
return Result.ok(validationResult.equals("ok"));
}
/**
* 用户邮箱验证码校验
*
* @param userEmail 用户邮箱
* @param authenticationCode 用户输入的验证码
* @return 校验失败时返回对应失败的字符串 ,否则返回 Ok
*/
public String securityCodeValidation(String userEmail, String authenticationCode) {
// 获取缓存数据中的邮箱验证码
String cacheData = redisTemplate.opsForValue().get(userEmail);
if (StrUtil.isBlank(cacheData)) {
return "验证码已过期,请重新获取";
}
// 缓存数据中的验证码
String securityCode = JSONObject.parseObject(cacheData).getString("securityCode");
if (!securityCode.equalsIgnoreCase(authenticationCode)) {
return "验证码无效";
}
return "ok";
}
大致流程就是这些了。