使用redis实现手机短信验证码和lua完成重置功能

文章目录


前言

2024了,各种各样的门户网站和APP都需要登录,登录方式也各种各样,由于都要绑定用户手机号码,所以大部分都支持了手机验证码登录的方式,接下来我们使用redis来完成验证码的功能。


一、介绍

方法名 描述
get 获取验证码
match 验证码配对
reset 验证码重置
check 手机号检测
sendVerificationCode 发送验证码

二、代码

1.LoginController

java 复制代码
@Controller
@RequestMapping("verificationCode")
public class LoginController {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private int maxRetryCount=3;
    private static final String COUNT="_COUNT";
    private static final String CODE="_CODE";
    private static final DefaultRedisScript<Boolean> RESET_SCRIPT;
    static {
        RESET_SCRIPT = new DefaultRedisScript<>();
        RESET_SCRIPT.setLocation(new ClassPathResource("redis/reset.lua"));
        RESET_SCRIPT.setResultType(Boolean.class);
    }
    @RequestMapping("get")
    @ResponseBody
    public boolean get(String phone){
        Optional.of(phone);
        if(check(phone)){
            return sendVerificationCode(phone);
        }
        return false;
    }
    @RequestMapping("match")
    @ResponseBody
    public boolean match(String phone, String code) {
        String redisCode = stringRedisTemplate.opsForValue().get(phone + CODE);
        System.out.println("用户["+phone+"],认证完成,跳转到首页!");
        return code.equals(redisCode);
    }
    @RequestMapping("reset")
    @ResponseBody
    public boolean reset(String phone) {
        boolean res=false;
        try {
            //用手机号拼接上字符串来作为key值,这是作为发送的次数
            String countKey = phone + COUNT;
            //用手机号拼接上字符串来作为key值,来表示你的验证码
            String codeKey = phone + CODE;
            if(stringRedisTemplate.execute(
                    RESET_SCRIPT,
                    Arrays.asList(countKey, codeKey))){
                res=true;
                System.out.println("重置已完成");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return res;
    }
    private boolean check(String phone) {
        String regex = "^1[0-9]{10}$"; // 定义手机号格式的正则表达式
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(phone);
        return matcher.matches();
    }
    private boolean sendVerificationCode(String phone){
        //用手机号拼接上字符串来作为key值,这是作为发送的次数
        String countKey = phone + COUNT;
        //用手机号拼接上字符串来作为key值,来表示你的验证码
        String codeKey = phone + CODE;
        try {
            //根据countKey来获取发送的次数
            String countStr = stringRedisTemplate.opsForValue().get(countKey);
            Integer count;
            try {
                //将String类型的次数来强转为Integer
                count = Integer.valueOf(countStr);
            }catch (NumberFormatException e){
                count = 0;
            }
            if(count > maxRetryCount){
                System.out.println("24小时内短信发送次数已达"+maxRetryCount+"次,不能继续发送!24小时后自动重置次数");
                //做判断来表示发送三次,再次发送失败
                return false;
            }
            //判断codeKey是否存在
            boolean isTtl = stringRedisTemplate.hasKey(codeKey);
            if(isTtl){
                //如果存在的获取还有多少秒过期
                long ttlCode = stringRedisTemplate.getExpire(codeKey);
                System.out.println("验证码在1分钟内保持有效,请于"+ttlCode+"秒之后再次发送");
                return false;
            }
            //获取6位数的随机数
            //这个地方如果换成手机短信的api接口的话就可以实现手机短信验证的功能
            String code = RandomUtil.randomNumbers(6);
            //保存在随机数中设置过期时间
            stringRedisTemplate.opsForValue().set(codeKey,code,1, TimeUnit.MINUTES);
            //设置过期时间为1天
            long timeOut = 24 * 60 * 60;
            //做一个判断如果不是第一次发送,就要根据countKey来获取他的剩余的过期时间
            if(count!=0){
                //如果这个地方是短信验证的功能的话就是可以换成根据countKey来获取它是否存在来判断是否验证码过期
                timeOut = stringRedisTemplate.getExpire(countKey);
            }
            stringRedisTemplate.opsForValue().set(countKey,String.valueOf(count+1),timeOut,TimeUnit.SECONDS);
            System.out.println("短信验证码发送完毕!请注意查收!");
            return true;
        }catch (Exception e){
            stringRedisTemplate.delete(codeKey);
            stringRedisTemplate.delete(countKey);
            return false;
        }
    }
}

2.reset.lua

lua 复制代码
-- reset.lua
local count = redis.call('get',KEYS[1])
if (count ~= nil) then
    redis.call('del',KEYS[1])
end
local code = redis.call('get',KEYS[2])
if (code ~= nil) then
    redis.call('del',KEYS[2])
end
return true

总结

回到顶部
官方文档对脚本的描述

相关推荐
BergerLee6 小时前
对不经常变动的数据集合添加Redis缓存
数据库·redis·缓存
huapiaoy6 小时前
Redis中数据类型的使用(hash和list)
redis·算法·哈希算法
【D'accumulation】7 小时前
令牌主动失效机制范例(利用redis)注释分析
java·spring boot·redis·后端
Cikiss7 小时前
微服务实战——SpringCache 整合 Redis
java·redis·后端·微服务
一休哥助手8 小时前
Redis 五种数据类型及底层数据结构详解
数据结构·数据库·redis
盒马盒马9 小时前
Redis:zset类型
数据库·redis
Jay_fearless11 小时前
Redis SpringBoot项目学习
spring boot·redis
Wang's Blog11 小时前
Redis: 集群环境搭建,集群状态检查,分析主从日志,查看集群信息
数据库·redis
wclass-zhengge17 小时前
Redis篇(最佳实践)(持续更新迭代)
redis·缓存·bootstrap
Dylanioucn17 小时前
【分布式微服务云原生】探索Redis:数据结构的艺术与科学
数据结构·redis·分布式·缓存·中间件