【架构设计】SpringBoot中使用Redis限制登录失败次数

业务场景

需求:为了防止枚举攻击,完成安全性测试扫描。需要限制登录失败次数限制,本文做的是累计登录失败五次账号锁定15min。(如果有一次登录成功则会重新计数)

架构设计

在这里插入图片描述

代码实现

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String STAFF_LOGIN_FAIL_COUNT = "STAFF:LOGIN:FAIL_COUNT:";

    private static final String STAFF_LOGIN_LOCK_FLAG = "STAFF:LOGIN:LOCK_FLAG:";

    @PostMapping("/login")
    public ResponseEx login(@RequestBody LoginParam param) {
        if ("LOCK".equals(redisTemplate.opsForValue().get(STAFF_LOGIN_LOCK_FLAG + req.getUserName()))) {
            return ResponseEx.createError("当前账号被锁定,请稍后再试");
        }
        //登录失败
        boolean loginFlag = false;
        if (!loginFlag) {
            redisTemplate.opsForValue().increment(STAFF_LOGIN_FAIL_COUNT + param.getUserName(), 1);
            redisTemplate.expire(STAFF_LOGIN_FAIL_COUNT + param.getUserName(), 1, TimeUnit.HOURS);
            if (Integer.parseInt(redisTemplate.opsForValue().get(STAFF_LOGIN_FAIL_COUNT + param.getUserName())) >= 5) {
                redisTemplate.opsForValue().set(STAFF_LOGIN_LOCK_FLAG + param.getUserName(), "LOCK", 1, TimeUnit.HOURS);
                return ResponseEx.createError("当前账号被锁定,请稍后再试");
            }
            return ResponseEx.createError("账号或密码错误!");
        }
        
        redisTemplate.opsForValue().set(STAFF_LOGIN_FAIL_COUNT + param.getUserName(), "0");

    }

逻辑抽象。避免类似的业务写重复的代码。

  • 判断是否被锁住
  • 次数累增
  • 清除次数抽象出来。
  • 想要过期时间定制化,需要优化。
/**
 * @author charles
 * @date 2023/5/5 16:56
 */
public class LockUtil {

    private static final String LOCK_KEY_PREFIX = "lock";

    private static final String COUNT_KEY_PREFIX = "count";

    private static final String COLON = ":";

    private static final String LOCK_FLAG = "LOCK";

    private static final Duration COUNT_EXPIRE_DURATION = Duration.ofHours(1L);
    
    private static final Duration LOCK_EXPIRE_DURATION = Duration.ofMinutes(15L);

    public static Boolean isLock(String bizKey) {
        StringRedisTemplate redisTemplate = SpringUtil.getBean(StringRedisTemplate.class);
        if (LOCK_FLAG.equals(redisTemplate.opsForValue().get(LOCK_KEY_PREFIX.concat(COLON).concat(bizKey)))) {
            return false;
        }
        return true;
    }

    public static Boolean plusCount(String bizKey) {
        StringRedisTemplate redisTemplate = SpringUtil.getBean(StringRedisTemplate.class);
        String countKey = COUNT_KEY_PREFIX.concat(COLON).concat(bizKey);
        String lockKey = LOCK_KEY_PREFIX.concat(COLON).concat(bizKey);
        redisTemplate.opsForValue().increment(countKey, 1);
        redisTemplate.expire(countKey, COUNT_EXPIRE_DURATION);
        if (Integer.parseInt(redisTemplate.opsForValue().get(countKey)) >= 5) {
            redisTemplate.opsForValue().set(lockKey, LOCK_FLAG, LOCK_EXPIRE_DURATION);
            return false;
        }
        return true;
    }

    public static void clearCount(String bizKey) {
        StringRedisTemplate redisTemplate = SpringUtil.getBean(StringRedisTemplate.class);
        String lockKey = LOCK_KEY_PREFIX.concat(COLON).concat(bizKey);
        redisTemplate.opsForValue().set(lockKey, "0");
    }
}

在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值