Java/Kotlin 使用Redis模拟发送验证码
原文地址: Java/Kotlin 使用Redis模拟发送邮件验证码 - Stars-One的杂货小窝
Java中常用语连接Redis的库有lettuce
和jredis
,一般是推荐lettuce
,其具有异步性,下面两种都简单来使用如何实现功能
jredis
1.引入依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
脚本使用:
fun main() {
//1.测试连接
val jedis = Jedis("127.0.0.1", 6379)
val resp = jedis.ping()
//为pong即为可用的
if (resp == "PONG") {
val key = "mykey"
val value = "hello world"
//写入数据
jedis[key]=value
//读数据
val result = jedis[key]
println(result)
// 删除指定key
val row = jedis.del(key)
//影响的行数
println(row)
//设置60s后过期
jedis.setex(key,60,value)
//设置60ms后过期
jedis.psetex(key,60,value)
//剩余的过期时间,ttl返回时间单位为s,pttl则是ms
val time = jedis.ttl(key)
val time = jedis.pttl(key)
}
}
通过setex
或psetex
方法来设置过期时间后,当数据过期后,再次去查询该数据,就会得到null(即redis将数据删除了)
上述也是简单演示了redis数据库的增删改查功能,下面就利用此数据库来实现发送验证码的功能。
2.发送验证码
这里我是实现了邮箱发送验证码的功能,验证码定为6位纯数字随机数,当然,你也可以加上大小写字母来提高复杂性。
之后我们将邮箱和验证码存储到redis中,并设置十分钟过期时间,随后通过调用邮箱发送邮件的方法,将验证码发送出去(这里详见JavaXMail发送邮件功能实现)
下面是验证码生成方法:
//生成验证码
fun randomCode(): String {
val sb = StringBuffer()
repeat(6) {
//0-9范围
val num = Random.nextInt(0, 10)
sb.append(num)
}
return sb.toString()
}
//发送验证码方法
fun sendCode(email: String) {
val code = randomCode()
//先判断redis是否有记录
val oldCode = RedisUtil.getValue(email)
val action = {
RedisUtil.setKeyValue(email, code)
//调用邮箱发送邮件方法
sendEmail(email, code)
}
if (oldCode.isBlank()) {
action.invoke()
} else {
//判断是否已过1分钟
//已过一分钟,重新发送,否则不做操作
val flag = RedisUtil.isGtOneMinutes(email)
if (flag) {
action.invoke()
}
}
}
object RedisUtil {
private val url = "127.0.0.1"
//10分钟
private const val expiredTime = 10 * 60
private val redis by lazy {
val jedis = Jedis(url, 6379)
//如果有设置密码
// jedis.auth("")
jedis
}
/**
* 获取数据
*/
fun getValue(key: String): String {
return redis[key] ?: ""
}
/**
* 存储邮箱和验证码
*/
fun setKeyValue(key: String, value: String) {
redis.setex(key, 10 * 60, value)
}
/**
* 获取指定key的剩余时间(s)
*/
fun getSurplusTime(key: String): Long {
return redis.ttl(key)
}
/**
* key是否已过1分钟
*/
fun isGtOneMinutes(key: String): Boolean {
val time = getSurplusTime(key)
//小于九分钟(说明已过1分钟)
return time <= expiredTime - 60
}
}
这里补充下,由于邮箱为用户输入,永远不要对用户输入抱有期待,用户可能输入不是个email地址或者输了个不存在的email地址,对于前者问题,我们可以通过在前端和后台增加一个邮箱格式验证,对于后者问题(不存在的email地址),没有什么验证办法,只有发送了才知道这个邮箱地址是否可用(可以使用try catch来捕获异常来处理)
所以如果发送邮件出现错误,我们需要进行对应的处理,把那条存储到redis数据删除,然后接口返回一个错误提示信息即可。
而且,为了考虑到恶意用户频繁操作,导致我们邮箱服务频繁发送邮件,我们也需要进行对应的考虑设置,这里只能顾全用户频繁输入单个邮箱的情况,如果是同个邮箱,我们设置验证码过了1分钟的时间,才给重新发送(即现在各大APP手机验证码的操作一样),前端和后台接口都是需要做限制。
如果是重新发送的话,我们需要重新setex
方法设置一下验证码,同时这步也将过期时间重置了。
3.校验验证码
之后就是考虑校验验证码的情况了,这里也是比较简单,通过拿到用户输入的验证码和redis里面的进行比对就可校验。
但可能会有特殊情况,比如redis验证码已经过期了,需要进行判断,并自动重新发送邮件,且接口返回提示信息
fun checkCode(email: String, code: String):Boolean {
val dbCode = RedisUtil.getValue(email)
if (dbCode.isBlank()) {
//重新发送邮件,并发送提示(这里省略了发送提示)
sendCode(email)
return false
} else {
if (dbCode==code) {
//验证通过
return true
}
return false
}
}
lettuce
Lettuce是一个高性能基于Java编写的Redis驱动框架,底层集成了Project Reactor提供天然的反应式编程,通信框架集成了Netty使用了非阻塞IO,5.x版本之后融合了JDK1.8的异步编程特性,在保证高性能的同时提供了十分丰富易用的API,5.1版本的新特性如下:
- 支持Redis的新增命令ZPOPMIN, ZPOPMAX, BZPOPMIN, BZPOPMAX。
- 支持通过Brave模块跟踪Redis命令执行。
- 支持Redis Streams。
- 支持异步的主从连接。
- 支持异步连接池。
- 新增命令最多执行一次模式(禁止自动重连)。
- 全局命令超时设置(对异步和反应式命令也有效)。
下面这里就稍微贴下代码就好,具体的思路上面已经都有提及了,就不再过多赘述了。
1.引入依赖
如果项目为Spring Boot,只需要引用spring-data-redis依赖即可,其内置默认使用lettuce此库来连接redis
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
或者是单独使用,则直接引用lettuce库即可
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
2.使用
val redisUri = RedisURI.builder() // <1> 创建单机连接的连接信息
.withHost("localhost")
.withPort(6379)
.withTimeout(Duration.of(10, ChronoUnit.SECONDS))
.build()
val redisClient = RedisClient.create(redisUri) // <2> 创建客户端
val connection = redisClient.connect() // <3> 创建线程安全的连接
val redisCommands = connection.sync() // <4> 创建同步命令
//这里的参数说明可以访问http://redis.io/commands/set查看
//ex就是设置5s的过期时间
val setArgs = SetArgs.Builder.nx().ex(5)
//获取剩余过期时间
redisCommands.ttl("name")
//设置数据
val result = redisCommands.set("name", "throwable", setArgs)
if (result.toLowerCase() == "ok") {
println("成功插入数据")
}
connection.close() // <5> 关闭连接
redisClient.shutdown() // <6> 关闭客户端
Lettuce结构比较复杂,上面罗列的基本使用已经够用了,就没有深入研究下去了...
其他
不过最近找了一款后台框架,写的时候发现,它是用的RedisTemplate,似乎比Lettuce要早一些的技术栈了,稍微摸索了下也能使用,也没去替换了那个后台框架里的东西了
//存入数据并设置时间
stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.HOURS);
//删除
stringRedisTemplate.delete(key);
//获取剩余到期时间
redisTemplate.getExpire(key, TimeUnit.MINUTES);
参考
- 使用Java操作Redis_java使用redis_一心同学的博客-CSDN博客
- RedisTemplate操作Redis,这一篇文章就够了(一)_ha_lydms的博客-CSDN博客
- Redis高级客户端Lettuce详解_lettuce客户端_倾听铃的声的博客-CSDN博客
Java/Kotlin 使用Redis模拟发送验证码的更多相关文章
- RabbitMQ+Redis模拟手机验证码登录
RabbitMQ+Redis模拟手机验证码登录 依赖 <dependency> <groupId>org.springframework.boot</groupId> ...
- 使用redis进行手机验证码的验证、每天只能发送三次验证码 (redis安装在虚拟机linux系统中)
文章目录 1.代码 2.测试结果 2.1.第一次发送 2.2.填写正确的验证码 2.3.填写错误的验证码 连续发送多次验证码 环境准备:虚拟机Linux系统,redis安装在虚拟机中. 前提条件:虚拟 ...
- 用java实现邮件发送验证码
java实现邮件发送验证码 建议不要用qq邮箱,我使用qq邮箱直接一直给我报530错误,我一直认为我代码写的有错误或者POP3/SMTP服务没弄好.所以建议注册个别的邮箱,我就申请了个网易163邮箱瞬 ...
- JAVA 实现 QQ 邮箱发送验证码功能(不局限于框架)
JAVA 实现 QQ 邮箱发送验证码功能(不局限于框架) 本来想实现 QQ 登录,有域名一直没用过,还得备案,好麻烦,只能过几天再更新啦. 先把实现的发送邮箱验证码更能更新了. 老规矩,更多内容在注释 ...
- java 阿里云接口实现发送短信验证码
此刻自己做的小项目中,需要用到手机发送短信验证码实现注册功能,于是就去阿里云注册了账号,并实现随机发送验证码的功能 第一步:在阿里云官网登录注册 已有支付宝或淘宝的账号可以直接登录,最后需要实名认 ...
- Java调用WebService接口实现发送手机短信验证码功能,java 手机验证码,WebService接口调用
近来由于项目需要,需要用到手机短信验证码的功能,其中最主要的是用到了第三方提供的短信平台接口WebService客户端接口,下面我把我在项目中用到的记录一下,以便给大家提供个思路,由于本人的文采有限, ...
- 【工具】java发送验证码邮件
文章目录 前言 配置邮箱服务器 代码实现 发送随机验证码与验证 后记 前言 要实现 可以设置格式,附件,抄送等功能,就跟真人操控邮箱发送邮件一样的功能,或许比较难,博主没研究,博主暂时没用到那些功能, ...
- 模拟安装redis5.0集群并通过Java代码访问redis集群
在虚拟机上模拟redis5.0的集群,由于redis的投票机制,一个集群至少需要3个redis节点,如果每个节点设置一主一备,一共需要六台虚拟机来搭建集群,此处,在一台虚拟机上使用6个redis实例来 ...
- 6、发送验证码功能(Redis)
一.业务需求: 1.后端随机生成短信验证码,并在服务器端保存一定时间(redis): 2.将短信验证码发给用户: 3.用户输入短信验证码提交后,在后端与之前生成的短信验证码作比较,如果相同说明验证成功 ...
- 【十次方微服务后台开发】Day01:环境、缓存(吐槽)、ES搜索文章、MQ注册时发送验证码
一.系统设计与工程搭建 1.需求分析 程序员的专属社交平台,包括头条.问答.活动.交友.吐槽.招聘 SpringBoot+SpringCloud+SpringMVC+SpringData全家桶架构 s ...
随机推荐
- js 获取年月日时分秒,星期
getDate() { var date = new Date() // 获取时间 var year = date.getFullYear() // 获取年 var month = date.getM ...
- LeetCode系列之 (JavaScript) => 53. 最大子数组和
题目描述: leetcode 题目链接: 53. 最大子数组和 - 力扣(LeetCode) (leetcode-cn.com) 解题思路分析: 题干最终的输出是连续子数组的最大和:1. 贪心算法: ...
- maven父子项目,由于pom文件中的<packaging>pom</packaging>导致报数据源配置错误
啊啊啊~~~ 又是踩坑的一天!!! 我在子模块中进行开发,然后子模块的pom文件中也写了<packaging>pom</packaging>导致报数据源配置错误.具体内容如下图 ...
- 第10章 带有依赖注入的服务配置(ASP.NET Core in Action, 2nd Edition)
第2部分 构建完整的应用程序 我们在第一部分中讨论了很多内容.您看到了ASP.NET Core应用程序是如何由中间件组成的,我们主要关注RazorPages框架.您了解了如何使用Razor语法构建传统 ...
- Ai2022中文版(Illustrator 2022)Mac/win v26.4.1
Adobe Illustrator 2022 Mac/win是设计行业中的矢量图形经典.数以百万计的设计人员和艺术家使用行业标准的矢量图形软件创作各类内容,从炫酷的 Web 和移动图形,到徽标.图标. ...
- WebApi 下载三维zip文件并预览
// 异步加载 const LoadObj = async (key?: string) => { LoadState.value = true var objStr, mtlStr var i ...
- 数据库自动备份,crontab定时任务
查看crontab运行状态service crond status 查看当前用户的crontab,输入 crontab -l: 编辑crontab,输入 crontab -e: 删除crontab,输 ...
- js数组常用的方法
var arr=['hello','前端','world']; 1. arr.join(分隔符):将数组中的值拼接成一个字符串,返回这个字符串,默认分隔符"," arr.join( ...
- ubuntu通过ftp向小米手机传输多个文件
输入ftp命令,连接手机 root@wanboo-Inspiron-5570:~# ftp 192.168.1.104 2121 Connected to 192.168.1.104. 220 Swi ...
- 狂神的学习笔记demo0607
Ctrl+D 复制此行到下一行 sout 快捷打出System.out.println(); 修饰符 static 静态的 finalf 常量 变量的命名规范 见名知意 类成员变量:首字母小写和驼 ...