很多地方都要用到重试次数限制,不然就会被暴力破解。比如登录密码。

下面不是完整代码,只是伪代码,提供一个思路。

第一种(先声明,这样写有个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解决“重试次数”场景的实现思路的更多相关文章

  1. redis数据类型及使用场景

    Redis数据类型  String: Strings 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字. 常用命令:  set,get,decr,incr,mge ...

  2. retry重试常见场景及实现

    当我们的代码是有访问网络相关的操作时,比如http请求或者访问远程数据库,经常可能会发生一些错误,有些错误可能重新去发送请求就会成功,本文分析常见可能需要重试的场景,并最后给出python代码实现. ...

  3. OkHttp自定义重试次数

    本文主要应用了OkHttp的Interceptor来实现自定义重试次数 虽然OkHttp自带retryOnConnectionFailure(true)方法可以实现重试,但是不支持自定义重试次数,所以 ...

  4. 170222、使用Spring Session和Redis解决分布式Session跨域共享问题

    使用Spring Session和Redis解决分布式Session跨域共享问题 原创 2017-02-27 徐刘根 Java后端技术 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用 ...

  5. SpringCloud Feign 之 超时重试次数探究

    SpringCloud Feign 之 超时重试次数探究 上篇文章,我们对Feign的fallback有一个初步的体验,在这里我们回顾一下,Fallback主要是用来解决依赖的服务不可用或者调用服务失 ...

  6. redis 实现登陆次数限制

    title: redis-login-limitation 利用 redis 实现登陆次数限制, 注解 + aop, 核心代码很简单. 基本思路 比如希望达到的要求是这样: 在 1min 内登陆异常次 ...

  7. Redis 客户端重试指南

    本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可. 在互联网服务中,特别是在云环境下,网络及硬件环境复杂,所有应用程序都可能遇到暂时性故障.暂时性故障包括瞬时的网络抖动,服务暂时不可 ...

  8. Redis数据库的使用场景介绍(避免误用Redis)

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/122.html?1455854235 Redis 是目前 NoSQL 领域 ...

  9. 豌豆夹Redis解决方式Codis源代码剖析:Proxy代理

    豌豆夹Redis解决方式Codis源代码剖析:Proxy代理 1.预备知识 1.1 Codis Codis就不详细说了,摘抄一下GitHub上的一些项目描写叙述: Codis is a proxy b ...

随机推荐

  1. python 定时任务 from apscheduler.schedulers.blocking import BlockingScheduler

    说明:使用python内置的模块来实现,本篇博客只是以循环定时来示范,其他的可以结合crontab的风格自己设定 一.导包 from apscheduler.schedulers.blocking i ...

  2. AlexNet梳理

    创新点 成功的使用relu函数替代了sigmoid函数,解决了使用sigmoid的梯度消散问题 成功的在全连接层使用dropout 成功的使用重叠最大池化 提出了LRN 利用GPU进行运算 数据增强2 ...

  3. JavaScript基础08——DOM

    DOM的概念 DOM是document Object Model的缩写,简称文档对象模型.他给文档提供了一种结构化的表示方式,可以改变文档的内容和呈现方式 所谓的DOM是以家族的形式描述HTML.父子 ...

  4. cube.js 集成cratedb 的尝试

    cratedb 提供了pg协议的兼容,我们可以直接使用pg client 连接,但是也不是完整实现pg 协议的 以下是 cube.js 集成cratedb 的一些尝试 环境准备 docker-comp ...

  5. 高考数学答卷策略[K12论坛转载]

    一.试卷上给你的启发 1.试卷上有参考公式,80%是有用的,它为你的解题指引了方向: 2.解答题的各小问之间有一种阶梯关系,通常后面的问要使用前问的结论.如果前问是证明,即使不会证明结论,该结论在后问 ...

  6. JavaScript语法-流程控制语句

    一.JavaScript特殊语法 JS特殊语法: 1. 语句以;结尾,如果一行只有一条语句则 ;可以省略 (不建议) 2. 变量的定义使用var关键字,也可以不使用 * 用: 定义的变量是局部变量 * ...

  7. ZROI 2020WC集训训练赛 Day4

    最后一场,幸好没有掉分,假装功德圆满吧. T1有各种数据结构做法,主要难点在优化空间. T2直接DP就完事了,然而记搜的复杂度是对的-- T3神仙最小割. 没错这篇文章就是咕了. pkuwc rp++ ...

  8. 一起学Makefile(四)

    变量的定义 makefile中的变量,与C语言中的宏类似,它为一个文本字符串(变量的值,其类型只能是字符串类型)提供了一个名字(变量名). 变量的基本格式: 变量名   赋值符   变量值 变量名指的 ...

  9. [golang][hugo]使用Hugo搭建静态站点

    使用Hugo搭建静态站点 hugo下载地址:https://github.com/gohugoio/hugo 模板列表:https://github.com/gohugoio/hugoThemes 开 ...

  10. Java中Set真的是无序的吗?

    我们经常听说List是有序且可重复的,Set是无序且不重复的.这是一个误区,这里所说的顺序有两个概念,一是按照添加的顺序排列,二是按,照自然顺序a-z排列.Set并不是无序的传统所说的Set无序指的是 ...