5 分钟内最多允许用户尝试登录3次,如果错误次数超过限制,需要对该用户进行锁定。如何实现?

这个问题,其实主要实现2个关键功能即可。

  1. 限制用户5分钟内最多尝试登录3次。
  2. 对用户进行锁定。

第一个功能,其实是一个典型的滑动窗口问题。

这个可以看看我的主页,有介绍

我们只需要构造一个滑动窗口,窗口大小限制5分钟,然后限流次数设置为3次即可实现这个功能了。而滑动窗口我们可以借助Redis来实现。

而第二个功能,我们只需要把被锁定的用户保存在Redis中即可,这样还能根据业务要求,设置一个合理的超时时间。

主要的实现代码如下:

java 复制代码
import redis.clients.jedis.Jedis;
public class SlidingWindowRateLimiter {
private Jedis jedis; private String key;
private int limit = 3; //限制请求次数最大3次private int lockTime; // 锁定用户的时间,单位:秒
public SlidingWindowRateLimiter(Jedis jedis, String key, int limit, int lockTime) {
this.jedis = jedis;
this.key = key;
this.limit = limit;
this.lockTime = lockTime; ( MH
public boolean allowRequest () {
// 当前时间戳,单位:毫秒
long currentTime = System. currentTimeMillis();
// 锁定键的名称(锁定的用户)
String lockKey = "lock:" + key;
// 检查用户是否已被锁定
if (jedis.exists(lockKey)) {
return false; // 用户已被锁定,返回 false
{
// 使用Lua脚本来确保原子性操作
String luascript = "local window_start = ARGV[1] - 300000\n" + // 计算5分钟的起始时间
"redis.call('ZREMRANGEBYSCORE',KEYS[1],'-inf',window_start)\n"+ // 清理过期的请求
"local current_requests = redis.call('ZCARD',KEYS [1])\n"+// 获取当前请求次数
"if current_requests < tonumber(ARGV[2])then\n"+ // 如果请求次数小于限制
_
redis.call('ZADD',KEYS [1],ARGV [1],ARGV[1])\n"+ // 添加当前请求时间return 1\n"+ // 允许请求
"elseln" +
redis.call('SET','lock:'..KEYS[1],1,'EX',tonumber(ARGV[3]))\n"+ // 锁定用户return O\n" + // 拒绝请求
"end";
// 调用 Lua 脚本进行原子操作
Object result = jedis.eval(luaScript, 1, key, String.valueOf(currentTime), String.valueOf(limit), String.valueOf(lockTime));
// 返回操作结果
return (Long) result == 1;
}
}

滑动窗口:滑动窗口的逻辑依然和原来一样,使用Redis 有序集合(ZADD)记录每次登录尝试的时间戳,过期的记录会被自动清理。

ZREMRANGEBYSCORE命令会移除当前时间窗口外的记录,确保统计的是最近 5 分钟内的登录尝试次数。

允许请求:如果在 5 分钟内的请求次数没有超过限制,脚本会将当前请求的时间戳添加到 Redis 的有序集合中,并返回 1,表示允许请求。

拒绝请求:如果用户在 5 分钟内的请求次数超过限制,脚本会设置用户的锁定键,并返回 ◎,表示拒绝请求。

用户锁定:在Lua 脚本中,我们使用 SET 命令在 Redis 中设置一个名为 lock:<user_id>的键,表示该

用户已经被锁定。当尝试次数超过限制时,设置这个锁,并给它一个过期时间(lockTime)。

锁定的用户无法再继续尝试登录,allowRequest()方法返回 false,表示该用户被锁定。

相关推荐
唐青枫21 分钟前
Java Maven 实战指南:从 POM、依赖管理到多模块构建
java
硕风和炜32 分钟前
【LeetCode: 1301. 最大得分的路径数目 + DP】
java·算法·leetcode·动态规划·dp·记忆化搜索
SamDeepThinking42 分钟前
面向对象真正管理的,不是对象,而是依赖
java·后端·程序员
剑挑星河月2 小时前
94.二叉树的中序遍历
java·算法·leetcode
2301_801184752 小时前
docker 工作
java·docker·容器
老前端的功夫2 小时前
【Java从入门到入土】47:构建工具:Maven与Gradle的战争
java·python·maven
aaPIXa6222 小时前
C++模板元编程:在编译期完成计算,实现零运行时开销
java·开发语言·c++
夜郎king2 小时前
RuoYi-Vue3 企业级后台快速落地实战指南
java·开发语言
二宝哥3 小时前
创建Gradle多模块SpringBoot项目
java·spring boot·后端
AI人工智能+电脑小能手3 小时前
【大白话说Java面试题 第156题】【06_Spring篇】第16题:Spring 用到了哪些设计模式?
java·spring·设计模式·代理模式·工厂模式