Redis如何实现验证码发送 以及限制每日发送次数


Posted in Redis onApril 18, 2022

1、功能

  • 输入手机号,点击发送后随机生成六位数字码,2分钟有效
  • 输入验证码,点击验证,返回成功或失败
  • 每个手机号每天只能输3次

2、分析

  • 每个手机每天只能输3次:incr每次发送之后+1,当值为3时提示不能发送,过期时间为当天结束
  • 随机生成6位数字验证码:RandomUtil(hutool)
  • 验证码2分钟有效:放入redis里并设置过期时间2分钟
  • 判断验证码是否一致:从redis里获取验证码和输入的验证码进行比对

3、实现

package cn.ken.blog.controller.common;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.ken.blog.common.constant.Constants;
import cn.ken.blog.common.domain.Result;
import cn.ken.blog.common.enums.ErrorCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 验证码控制器
 * @author Ken-Chy129
 * @date 2022/4/17 20:28
 */
@RestController
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public class CaptureController {
    
    @Autowired
    private RedisTemplate redisTemplate;
    
    // 生成验证码
    @GetMapping("getNumCode")
    public Result<String> getNumCode(String phone) {
        String captureLimitKey = Constants.CAPTCHA_LIMIT_KEY + phone;
        Integer counts = (Integer) redisTemplate.opsForValue().get(captureLimitKey);
        if (ObjectUtils.isEmpty(counts)) {
            // 今天第一次验证,故之前缓存中无该键
            // 距离今天结束剩下多少毫秒
            long expire = DateUtil.endOfDay(new Date()).between(new Date(), DateUnit.MS);
            redisTemplate.opsForValue().set(captureLimitKey, 1, expire, TimeUnit.MILLISECONDS);
        } else if (counts < 3) {
            // 没有超过限制次数
            redisTemplate.opsForValue().increment(captureLimitKey);
        } else {
            // 超过限制次数,不生成验证码,直接返回
            return new Result<String>().error(ErrorCodeEnum.OVER_LIMITS);
        }
        // 生成验证码
        String code = RandomUtil.randomNumbers(6); // 随机生成六位数
        String captureCodeKey = Constants.CAPTCHA_CODE_KEY + phone;
        redisTemplate.opsForValue().set(captureCodeKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        return new Result<String>().success(captureCodeKey + ":" + code);
    }
    
    // 验证验证码
    @GetMapping("verify")
    public Result<String> verify(String phone, String code) {
        String captureCodeKey = Constants.CAPTCHA_CODE_KEY + phone;
        String realCode = (String) redisTemplate.opsForValue().get(captureCodeKey);
        if (ObjectUtils.isEmpty(realCode)) {
            // redis中不存在该用户生成的验证码,证明验证码以过期销毁
            return new Result<String>().error(ErrorCodeEnum.OVERDUE_CODE);
        }
        if (realCode.equals(code)) {
            return new Result<String>().success("验证成功");
        } else {
            return new Result<String>().error(ErrorCodeEnum.ERROR_CODE);
        }
    }
    
//    @Scheduled(cron = "0 0 12 * * ?")
//    private void clear() {
//        redisTemplate.delete()
//    }
}
// Constants类

/**
 * 验证码 redis key
 */
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";

/**
 * 每日限制 redis key
 */
public static final String CAPTCHA_LIMIT_KEY = "captcha_limits:";
/**
 * 验证码有效期(分钟)
 */
public static final Integer CAPTCHA_EXPIRATION = 2;

到此这篇关于Redis实现验证码发送并限制每日发送次数的示例代码的文章就介绍到这了!

Redis 相关文章推荐
Redis遍历所有key的两个命令(KEYS 和 SCAN)
Apr 12 Redis
详解Redis实现限流的三种方式
Apr 27 Redis
深入浅析Redis 集群伸缩原理
May 15 Redis
浅谈Redis的几个过期策略
May 27 Redis
redis使用不当导致应用卡死bug的过程解析
Jul 01 Redis
redis不能访问本机真实ip地址的解决方案
Jul 07 Redis
详解Redis在SpringBoot工程中的综合应用
Oct 16 Redis
Redis 持久化 RDB 与 AOF的执行过程
Nov 07 Redis
解决Redis启动警告问题
Feb 24 Redis
利用Redis实现点赞功能的示例代码
Jun 28 Redis
redis lua限流算法实现示例
Jul 15 Redis
Redis实战高并发之扣减库存项目
Redis中key的过期删除策略和内存淘汰机制
解决 Redis 秒杀超卖场景的高并发
redis 解决库存并发问题实现数量控制
Redis超详细讲解高可用主从复制基础与哨兵模式方案
redis复制有可能碰到的问题汇总
Apr 03 #Redis
 Redis 串行生成顺序编码的方法实现
You might like
用Php实现链结人气统计
2006/10/09 PHP
PHP cron中的批处理
2008/09/16 PHP
php 数组排序 array_multisort与uasort的区别
2011/03/24 PHP
php中批量修改文件后缀名的函数代码
2011/10/23 PHP
php实现事件监听与触发的方法
2014/11/21 PHP
PHP通过API获取手机号码归属地
2015/05/28 PHP
php通过文件头判断格式的方法
2016/05/28 PHP
Laravel实现表单提交
2017/05/07 PHP
经典的带阴影的可拖动的浮动层
2006/06/26 Javascript
JavaScript写的一个DIV 弹出网页对话框
2009/08/14 Javascript
jQuery学习笔记之DOM对象和jQuery对象
2010/12/22 Javascript
jQuery解析XML文件同时动态增加js文件的方法
2015/06/01 Javascript
Jquery ajax 同步阻塞引起的UI线程阻塞问题
2015/11/17 Javascript
详解Document.Cookie
2015/12/25 Javascript
使用Promise解决多层异步调用的简单学习心得
2016/05/17 Javascript
BootStrap Progressbar 实现大文件上传的进度条的实例代码
2016/06/27 Javascript
AngularJS入门教程之AngularJS 模板
2016/08/18 Javascript
JS失效 提示HTML1114: (UNICODE 字节顺序标记)的代码页 utf-8 覆盖(META 标记)的冲突的代码页 utf-8
2017/06/23 Javascript
JavaScript动态绑定详解
2017/09/14 Javascript
Echarts之悬浮框中的数据排序问题
2018/11/08 Javascript
基于vue和websocket的多人在线聊天室
2020/02/01 Javascript
如何使用 JavaScript 操作浏览器历史记录 API
2020/11/24 Javascript
[02:27]2014DOTA2国际邀请赛 VG赛后采访:更大的挑战在等着我们
2014/07/13 DOTA
[01:03:22]LGD vs OG 2018国际邀请赛淘汰赛BO3 第一场 8.25
2018/08/29 DOTA
在Python中使用列表生成式的教程
2015/04/27 Python
python求解水仙花数的方法
2015/05/11 Python
pandas的排序和排名的具体使用
2019/07/31 Python
python 基于UDP协议套接字通信的实现
2021/01/22 Python
免费获得微软MCSD证书赶快行动吧!
2012/11/13 HTML / CSS
Sunglasses Shop瑞典:欧洲领先的太阳镜网上商店
2018/04/22 全球购物
巴塞罗那观光通票:Barcelona Pass
2019/10/30 全球购物
编程实现当输入某产品代码则打印出该产品记录的功能
2014/05/03 面试题
必须要使用游标的SQL语句有那些
2012/05/07 面试题
软件测试题目
2013/02/27 面试题
小学毕业感言300字
2014/02/19 职场文书
青年人初次创业的“五不要”
2019/08/23 职场文书