Redis解决“重试次数”场景的实现思路
很多地方都要用到重试次数限制,不然就会被暴力破解。比如登录密码。
下面不是完整代码,只是伪代码,提供一个思路。
第一种(先声明,这样写有个bug)
import java.text.MessageFormat;
public class Demo {
/**
* 限制次数
*/
private static final Integer MAX_TIMES = 5;
/**
* 锁定时间(也是key的失效时间)
*/
private static final Integer LIMIT_TIME = 3;
/**
* key
*/
private static final String LIMIT_TIMES_KEY = "LimitTimesKey:%s";
public void deal(String phone, String password){
// 用户id
Long userId = 6815356L;
// 组装key
String key = MessageFormat.format(LIMIT_TIMES_KEY, userId);
// 先获取key对应的value
String s = redisService.get(key);
int currentTimes = s != null ? Integer.parseInt(s) : 0;
// 如果当前次数为[LIMIT_TIMES]次或以上,则抛异常
if(currentTimes >= MAX_TIMES){
throw new RuntimeException("请在"+ LIMIT_TIME +"分钟后继续尝试");
}
// TODO 做其它逻辑,比如登录操作
Integer code = userService.login(phone, password);
// 比如密码不正确的状态码是10086
if(code == 10086){
// 失败次数+1
int thisTimes = currentTimes + 1;
String value = String.valueOf(thisTimes);
// 如果小于最大限制
if(thisTimes < MAX_TIMES){
redisService.set(key, value);
throw new RuntimeException("原密码错误,还可以重试"+ (MAX_TIMES - thisTimes) +"次");
}else{
redisService.setex(key, LIMIT_TIME*60, value);
throw new RuntimeException("原密码错误,请在"+ LIMIT_TIME +"分钟后继续尝试");
}
}
// 登陆成功,清理redis
redisService.del(key);
}
}
以上代码思路:

以上代码有什么问题呢:当失败次数小于最大限制,那里直接set了一个值,没有设置失效时间。如果用户失败了一次就不再尝试了,那么我们设置的key就会永远存在;同时用户在n年后再去登陆,他拥有的重试次数是凌驾于n年前的重试次数之上的,也就是说我今年浪费了1次重试次数,还剩下4次,我明年再重试,我能够重试的次数就不是5而是4了,因为我的重试次数记录一直存在。
import java.text.MessageFormat;
public class Demo {
/**
* 限制次数
*/
private static final Integer MAX_TIMES = 5;
/**
* 锁定时间(也是key的失效时间)
*/
private static final Integer LIMIT_TIME = 3;
/**
* key
*/
private static final String LIMIT_TIMES_KEY = "LimitTimesKey:%s";
public void deal(String phone, String password){
// 用户id
Long userId = 6815356L;
// 组装key
String key = MessageFormat.format(LIMIT_TIMES_KEY, userId);
// 先获取key对应的value
String s = redisService.get(key);
int currentTimes = s != null ? Integer.parseInt(s) : 0;
// 如果当前次数为[LIMIT_TIMES]次或以上,则抛异常
if(currentTimes >= MAX_TIMES){
throw new RuntimeException("请在"+ LIMIT_TIME +"分钟后继续尝试");
}
// TODO 做其它逻辑,比如登录操作
Integer code = userService.login(phone, password);
// 比如密码不正确的状态码是10086
if(code == 10086){
// 失败次数+1
int thisTimes = currentTimes + 1;
String value = String.valueOf(thisTimes);
// 设置值,重点是失效时间
redisService.setex(key, LIMIT_TIME*60, value);
// 如果小于最大限制
if(thisTimes < MAX_TIMES){
throw new RuntimeException("原密码错误,还可以重试"+ (MAX_TIMES - thisTimes) +"次");
}else{
throw new RuntimeException("原密码错误,请在"+ LIMIT_TIME +"分钟后继续尝试");
}
}
// 登陆成功,清理redis
redisService.del(key);
}
}
改进之后的思路如下:

Redis解决“重试次数”场景的实现思路的更多相关文章
- redis数据类型及使用场景
Redis数据类型 String: Strings 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字. 常用命令: set,get,decr,incr,mge ...
- retry重试常见场景及实现
当我们的代码是有访问网络相关的操作时,比如http请求或者访问远程数据库,经常可能会发生一些错误,有些错误可能重新去发送请求就会成功,本文分析常见可能需要重试的场景,并最后给出python代码实现. ...
- OkHttp自定义重试次数
本文主要应用了OkHttp的Interceptor来实现自定义重试次数 虽然OkHttp自带retryOnConnectionFailure(true)方法可以实现重试,但是不支持自定义重试次数,所以 ...
- 170222、使用Spring Session和Redis解决分布式Session跨域共享问题
使用Spring Session和Redis解决分布式Session跨域共享问题 原创 2017-02-27 徐刘根 Java后端技术 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用 ...
- SpringCloud Feign 之 超时重试次数探究
SpringCloud Feign 之 超时重试次数探究 上篇文章,我们对Feign的fallback有一个初步的体验,在这里我们回顾一下,Fallback主要是用来解决依赖的服务不可用或者调用服务失 ...
- redis 实现登陆次数限制
title: redis-login-limitation 利用 redis 实现登陆次数限制, 注解 + aop, 核心代码很简单. 基本思路 比如希望达到的要求是这样: 在 1min 内登陆异常次 ...
- Redis 客户端重试指南
本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可. 在互联网服务中,特别是在云环境下,网络及硬件环境复杂,所有应用程序都可能遇到暂时性故障.暂时性故障包括瞬时的网络抖动,服务暂时不可 ...
- Redis数据库的使用场景介绍(避免误用Redis)
转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/122.html?1455854235 Redis 是目前 NoSQL 领域 ...
- 豌豆夹Redis解决方式Codis源代码剖析:Proxy代理
豌豆夹Redis解决方式Codis源代码剖析:Proxy代理 1.预备知识 1.1 Codis Codis就不详细说了,摘抄一下GitHub上的一些项目描写叙述: Codis is a proxy b ...
随机推荐
- 第八次 Java 作业 重写正方形周长方法
# 题目 编写一个应用程序,创建一个矩形类,类中具有长.宽两个成员变量和求周长的方法. 再创建一个矩形类的子类——正方形类,类中定义求面积方法.重写求周长的方法. 在主类中,输入一个正方形边长,创建正 ...
- jquery 获取 新添加元素 点击后 的子元素
$("body").on("click", '.tabletr1', (event) => { debugger var ID2 = $(event.ta ...
- timeout/timelimit
timelimit
- rsync同步备份
一.服务器端.备份客户端安装 rsync 服务. 1.环境: CentOS 主 IP:172.16.3.18 备 IP:172.16.3.19 2.安装 rsync 软件 #yum install r ...
- [Cqoi2016]K远点对 K-Dtree
4520: [Cqoi2016]K远点对 链接 bzoj 思路 用K-Dtree求点的最远距离. 求的时候顺便维护一个大小为2k的小根堆. 不知道为啥一定会对. 代码 #include <bit ...
- access us
Ubuntu下设置 chrome的SwitchyOmega Wiki (简体中文)wiki Linux安装配置客户端及开机自动启动 运维 安装 配置 搭建服务以及配置多用户 安装和配置 一键搭建 服务 ...
- 小说美句摘抄&&动漫壁纸
不知道为啥脑子一抽打算开个坑(反正咱是个不务正业的人) 大部分是网文里的,某些是轻小说里的,文学名著--咱也不像会看那个的人啊-- upd 2019.11.6:把一些自己觉得好的动漫壁纸贴一贴,图床用 ...
- 【luoguP5490】【模板】扫描线
求\(n\)个矩形的面积并,可以用线段树维护一条垂直于\(y\)轴的直线上被矩形覆盖的长度有多少长,将直线从左往右扫一遍,遇到矩形左边界就+1,遇到右边界就-1,不为\(0\)的位置就表示没有覆盖 不 ...
- TensorFlow 报错 ValueError: Can't load save_path when it is None.
原因 : 模型还未生成出来 , 此时你去检测的生成完毕的模型 , 模型呢 ? 还没生成 . 模型还没生成就引用了为什么不报错 ? 解决办法 : 当前情况不要以为是你的程序有 bug , 而是你的模型还 ...
- [Beta阶段]第十次Scrum Meeting
Scrum Meeting博客目录 [Beta阶段]第十次Scrum Meeting 基本信息 名称 时间 地点 时长 第十次Scrum Meeting 19/05/16 大运村寝室6楼 30min ...