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 ...
 
随机推荐
- 洛谷P1352 没有上司的舞会题解
			
题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...
 - 计蒜客 41387.XKC's basketball team-线段树(区间查找大于等于x的最靠右的位置) (The Preliminary Contest for ICPC Asia Xuzhou 2019 E.) 2019年徐州网络赛
			
XKC's basketball team XKC , the captain of the basketball team , is directing a train of nn team mem ...
 - bootstrap入门&栅格系统
			
一.概述 1. 概念: 一个前端开发的框架,Bootstrap,来自 Twitter,是目前很受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JavaScript 的,它简洁灵活,使得 ...
 - 本地局域网yum源搭建-centos/redhat
			
环境-centos6.7 [本机yum搭建提前备好,不做介绍] [root@nagios ~]# cat /etc/redhat-release CentOS release 6.7 (Final) ...
 - dubbo源码分析之过滤器Filter-12
			
https://blog.csdn.net/luoyang_java/article/details/86682668 Dubbo 是阿里巴巴开源的一个高性能优秀的服务框架,使得应用可通过高性能的 R ...
 - Java基础 awt Frame 窗体的大小不可调
			
JDK :OpenJDK-11 OS :CentOS 7.6.1810 IDE :Eclipse 2019‑03 typesetting :Markdown code ...
 - springboot vue前后端分离 跨跨域配置
			
public class CustomCorsFilter extends OncePerRequestFilter { @Override protected void doFilterIntern ...
 - js比较时间大于6个月
			
//mons是比较的月数,如 2019-02-01 14:27:08 - 2019-08-01 14:27:08 function compareTime(mons,stTime,endTime){ ...
 - 【转载】        TensorFlow学习——tf.GPUOptions和tf.ConfigProto用法解析
			
原文地址: https://blog.csdn.net/c20081052/article/details/82345454 ------------------------------------- ...
 - 解决python3.7无法使用HTMLTestRunner.py生成html测试报告的问题2019.04
			
**一:首先下载这个HTMLTestRunner.py文件:链接: https://pan.baidu.com/s/1jQFsMYLM3ysY6shgRF40Kw 提取码: evq2二:把该文件放在p ...