视频直播app源码,利用缓存实现连续登录失败后的时间等待
实现步骤:
1、用户在视频直播app源码中发起登录请求
2、后台验证是否失败次数过多,账户没有锁定的话就进入下面的步骤;否则直接返回
3、验证用户的账号 + 密码
3.1 验证成功:删除缓存
3.2 验证失败:统计最近10分钟时间窗口内的失败次数,如果达到5次则设置锁定缓存,返回
图解实现步骤:
代码实现细节:
登录失败计数器的key设计为:一串字符串 + 用户名(假设具有唯一性)+ 登录失败的时间
锁定登录操作的key设计为:一串字符串 + 用户名(假设具有唯一性)
private static final String FAIL_COUNT_REDIS_KEY = "login_fail_count"; private static final String LOCK_REDIS_KEY = "login_lock"; private static final String SEPARATOR = ":";
用户登录服务:
@Override public String login(String username, String password) { // 验证用户是否被登录锁定 boolean lock = isForbidden(username); if (lock) { return "Login authentication failed too many times. Please try again after " + unLockTime(username) + " minutes."; } // 验证用户名 + 密码 boolean isLogin = userRepository.checkUsernameAndPassword(username, password); if (!isLogin) { // 登录失败 setFailCounter(username); return "login fail"; } // 登录成功 移除失败计数器 deleteFilCounter(username); return "login success"; }
登陆失败的话,就给登录失败次数加一:
@Override public void setFailCounter(String username) { // 获取当前时间 Calendar cal = Calendar.getInstance(); String minute = fastDateFormat.format(cal); // 登录失败次数 + 1 String key = String.join(SEPARATOR, FAIL_COUNT_REDIS_KEY, username, minute); Integer count = redisTemplate.opsForValue().get(key); redisTemplate.opsForValue().increment(key, 1); // 如果key不存在的话就会以增量形式存储进来 if (count == null) { redisTemplate.expire(key, 10, TimeUnit.MINUTES); } // 如果失败次数大于5次,锁定账户 List<String> windowsKeys = new ArrayList<>(); for (int i = 0; i < 10; i ++) { windowsKeys.add(String.join(SEPARATOR, FAIL_COUNT_REDIS_KEY, username, fastDateFormat.format(cal))); cal.add(Calendar.MINUTE, -1); } List<Integer> countList = redisTemplate.opsForValue().multiGet(windowsKeys); assert countList != null; int total = 0; for (Integer c : countList) { total += c; } if (total >= maxFailTimes) { forbidden(username); } }
如果登录成功,则删除失败次数计数器:
@Override public void deleteFilCounter(String username) { Calendar cal = Calendar.getInstance(); List<String> windowKeys = new ArrayList<>(); for (int i = 0; i < 10; i ++) { windowKeys.add(String.join(SEPARATOR, FAIL_COUNT_REDIS_KEY, username, fastDateFormat.format(cal))); cal.add(Calendar.MINUTE, -1); } redisTemplate.delete(windowKeys); }
失败次数超过5次则禁止登录,只需要设置一个缓存即可:
@Override public void forbidden(String username) { String key = String.join(SEPARATOR, FAIL_COUNT_REDIS_KEY, username); redisTemplate.opsForValue().set(key, 1, 30, TimeUnit.MINUTES); }
判断是否被禁止登录,只需要判断是否有上面方法设置的key即可:
@Override public boolean isForbidden(String username) { try{ return Boolean.TRUE.equals(redisTemplate.hasKey(String.join(SEPARATOR, FAIL_COUNT_REDIS_KEY, username))); }catch (Exception e){ e.printStackTrace(); } return false; }
如果想要获取到用户具体需要几分钟才能解锁(用于提示信息),只需要查询缓存的过期时间:
private Long unLockTime(String username){ String key = String.join(SEPARATOR, LOCK_REDIS_KEY, username); Long expireTime = redisTemplate.opsForValue().getOperations().getExpire(key, TimeUnit.MINUTES); if (expireTime == null){ throw new RuntimeException("there is no unlock time"); } return expireTime; }
以上就是视频直播app源码,利用缓存实现连续登录失败后的