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

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

第一种(先声明,这样写有个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. windows使用 xxx.bat运行相关指令

    今日思语:成人的世界,请停止低层次的忙碌 一般是windows上需要执行一些支持的命令时,我们一般都会直接使用控制台去操作,对于需要频繁操作的指令来说,使用控制台略显有些不便,比如不小心关闭后控制台后 ...

  2. iOS 逆向工程(工具介绍)- 学习整理(转)

    一.class-dump 简介:顾名思义,就是用来导出目标对象的class信息的工具,私有方法声明也能导出来. 原理:利用 Objective-C语言的 runtime 特性,将存 在Mach-O 文 ...

  3. [PHP] Laravel 5.5 使用备注

    laravel-5_5文档地址:https://laravelacademy.org/category/laravel-5_5 模板变量文档: https://laravelacademy.org/p ...

  4. allure 2

    项目地址 https://github.com/allure-framework/allure2/releases 安装文档 https://docs.qameta.io/allure/#_insta ...

  5. bzoj5461 Minimax 题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5461 看到题目,必将m种权值离散化. 首先是一个显然的dp设计. 设$f(i,j)$表示第i个节点 ...

  6. sql脱库的几种方法

    当发现sql注入之后,脱库的方法,有以下几种:   (1)当目标主机支持外部连接时,使用Navicat 进行连接!当时目标主机不同,使用的Navicat种类不一样: mysql : Navicat f ...

  7. Mercurial 安装及使用

      版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/moonspiritacm/articl ...

  8. PHP 命令行参数解析工具类

    <?php/** * 命令行参数解析工具类 * @author guolinchao * @email luoyecb@163.com */class CommandLine{ // store ...

  9. 多线程高效合作之master-warker模式

    对于高并发的任务,有些任务是相互独立的,任务与任务之间没有依赖关系,因此可以采用 master - worker 模式. master 用于接受任务和分发任务给 worker,并将 worker 返回 ...

  10. hangfire 实现已完成的job设置过期,防止数据无限增长

    1.添加SucceededStateExpireHandler 继承接口 IStateHandler public class SucceededStateExpireHandler : IState ...