0to1使用Redis实现“登录验证”次数限制

1 引言

系统为了避免密码遭到暴力破解,通常情况下需要在登录时,限制用户验证账号密码的次数,当达到一定的验证次数后,在一段时间内锁定该账号,不再验证。本章将用几行代码实现该功能,完整代码链接在文章最后。

2 原理介绍

可以看到在登录接口中,4行代码即可实现该功能,这里使用Redis可以很方便的记录"登录失败次数",以及设置其失效时间(即锁定时间),主要步骤是:

  1. 账号登录时,当前账号"登录失败次数"默认+1。
  2. 设置"登录失败次数"失效的时间(即锁定时间)。
  3. 当"登录失败次数"大于某个阈值时,就直接返回错误提示,不再走验证逻辑。
  4. 账号登录成功,清除"登录失败次数",重新计数。

注意:第2步和第3步,可以交换顺序。

第2步在前时,锁定中发起请求会导致重新计时。

第3步在前时,锁定中发起请求不会导致重新计时。

3 代码

isTrue是断言方法,不满足条件时,抛出异常,在全局异常处理中,统一返回错误提示。参见Spring全局异常处理HandlerExceptionResolver使用。

复制代码
package com.zeroone.service.sys;

import com.zeroone.common.RedisKey;
import com.zeroone.entity.sys.User;
import com.zeroone.service.BaseService;
import com.zeroone.utils.Param;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;


@Service("UserService")
public class LoginServiceImpl extends BaseService implements LoginService {


    @Override
    public Object webLogin(Param info) {
        String account = info.getStringNotNull("account").trim();
        String password = info.getStringNotNull("password").trim();

        Long loginFailedCount = redisTemplate.opsForValue().increment(RedisKey.LOGIN_FAILED_COUNT + account, 1);//先将登录失败次数+1
        redisTemplate.expire(RedisKey.LOGIN_FAILED_COUNT + account, 10, TimeUnit.SECONDS);// 指定登录失败次数失效时间
        isTrue(loginFailedCount <= 5, "请10秒后重试!");//当登录失败次数大于阈值后,直接返回错误信息
        //TODO 模拟验证密码
        isTrue(password.equals("12345"), "账号或密码错误,还能重试" + (5 - loginFailedCount) + "次!");
        redisTemplate.delete(RedisKey.LOGIN_FAILED_COUNT + account);// 验证通过后,清除登录失败次数

        User user = new User();
        user.setId(1L);
        user.setName("张三");
        user.setAccount("12345678901@qq.com");
        user.setPhone("12345678901");
        String token = tokenService.createToken(user);
        return token;
    }

    @Override
    public void logout() {
        tokenService.deleteToken();
    }
}

    /**
     * true断言
     *
     * @param expression 参数
     * @param msg        描述
     */
    public void isTrue(boolean expression, String msg) {
        if (!expression) {
            throw new MyRuntimeException(HttpCode.BAD_REQUEST_CODE, msg);
        }
    }

4 测试

  1. 启动项目,请求:http://localhost:8080/web/login,输入错误的密码,提示"账号或密码错误,还能重试X次!"。
  1. 然后连续验证错误5次后,提示"请10秒后重试!",表示该账号被锁定,拒绝验证,且10秒内无法再次请求验证。

5 完整代码

Gitee代码链接

相关推荐
T_Wizard8 分钟前
同一个问题写了 4 遍:官方 SDK / HTTP / Spring AI / LangChain4j,到底该选哪个
java·ai编程
hai_android10 分钟前
AudioTrack 深度解析:从原理到实战
android·java·kotlin
斯维赤32 分钟前
限流、熔断、降级,你真的分得清吗?
java·后端·架构
2601_967987371 小时前
安装 Redis 或 Redis Stack
linux·windows·redis·macos·安装
小番茄程序猿3 小时前
Redis 编码压测 59 轮:HSET 快 23 倍是假象,SMEMBERS 慢 30 倍是真的
redis·后端
aiks_yuan3 小时前
Java CPU 100% 怎么排查:JDK 11 起 jstack 自带线程 CPU 时间,不用再 top -H 换算十六进制(JDK 8、11、17 实测)
java
鶴哥只手遮天4 小时前
《Redis 8.10.3 深度剖析》系列 ·第 13 章 Set:三种编码、集合运算与随机采样
redis·后端·开源
Flynn Liang5 小时前
AiServices 源码级拆解:一个接口如何变成 RAG Agent
java·langchain·源码分析·rag·langchain4j·aiservices
Flynn Liang5 小时前
LangChain4j 1.23 架构全景:Java 大模型应用的 6 层抽象
java·langchain·大模型·rag·ai agent·langchain4j
聪明的笨猪猪6 小时前
实际工程问题:AI生成Redis分布式锁的原子性缺陷导致库存超卖
java·经验分享·面试·ai编程