All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.seepine.auth.util.RateLimitUtil Maven / Gradle / Ivy

package com.seepine.auth.util;

import com.seepine.auth.entity.RateLimitEntity;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

/**
 * @author seepine
 */
@Slf4j
public class RateLimitUtil {
  private static final String LIMIT_KEY = "com.seepine.auth.rate_limit:";
  private static final Base64.Encoder base64Encoder = Base64.getEncoder();

  private RateLimitUtil() {}

  /**
   * 验证是否速率限制
   *
   * @param second 秒速率,如5,则一秒最多只能访问5次
   * @param minute 分速率,同上
   * @param hour 时速率
   * @param day 天速率
   * @param global 是否全局共享
   * @return true/false
   */
  public static boolean verify(int second, int minute, int hour, int day, boolean global) {
    String uniqueId = getUniqueId(global);
    Object cache = RedissonUtil.get(LIMIT_KEY + uniqueId);
    RateLimitEntity entity;
    try {
      if (cache == null) {
        throw new Exception();
      }
      entity = (RateLimitEntity) cache;
    } catch (Exception e) {
      entity = new RateLimitEntity();
      entity.init();
      RedissonUtil.set(LIMIT_KEY + uniqueId, entity, 25, TimeUnit.HOURS);
      return true;
    }
    LocalDateTime now = LocalDateTime.now();

    // 相差超过1天
    if (beyond(entity.getLastDayTime(), now, TimeUnit.DAYS)) {
      entity.init();
    }
    // 不超过1天
    else {
      // 超过1小时
      if (beyond(entity.getLastHourTime(), now, TimeUnit.HOURS)) {
        entity.setDay(entity.getDay() + 1);
        entity.setHour(1);
        entity.setMinute(1);
        entity.setSecond(1);
        entity.setLastHourTime(now);
        entity.setLastMinuteTime(now);
        entity.setLastSecondTime(now);
      }
      // 不超过1小时
      else {
        // 超过1分钟
        if (beyond(entity.getLastMinuteTime(), now, TimeUnit.MINUTES)) {
          entity.setDay(entity.getDay() + 1);
          entity.setHour(entity.getHour() + 1);
          entity.setMinute(1);
          entity.setSecond(1);
          entity.setLastMinuteTime(now);
          entity.setLastSecondTime(now);
        }
        // 不超过1分钟
        else {
          // 超过1秒钟
          if (beyond(entity.getLastSecondTime(), now, TimeUnit.SECONDS)) {
            entity.setDay(entity.getDay() + 1);
            entity.setHour(entity.getHour() + 1);
            entity.setMinute(entity.getMinute() + 1);
            entity.setSecond(1);
            entity.setLastSecondTime(now);
          }
          // 不超过1秒钟
          else {
            entity.setDay(entity.getDay() + 1);
            entity.setHour(entity.getHour() + 1);
            entity.setMinute(entity.getMinute() + 1);
            entity.setSecond(entity.getSecond() + 1);
          }
        }
      }
    }
    RedissonUtil.set(LIMIT_KEY + uniqueId, entity, 25, TimeUnit.HOURS);
    if (second > 0 && entity.getSecond() > second) {
      log.debug("{}超出秒请求限制,限制数{},请求数{}", uniqueId, second, entity.getSecond());
      return false;
    }
    if (minute > 0 && entity.getMinute() > minute) {
      log.debug("{}超出分请求限制,限制数{},请求数{}", uniqueId, minute, entity.getMinute());
      return false;
    }
    if (hour > 0 && entity.getHour() > hour) {
      log.debug("{}超出时请求限制,限制数{},请求数{}", uniqueId, hour, entity.getHour());
      return false;
    }
    if (day > 0 && entity.getDay() > day) {
      log.debug("{}超出天请求限制,限制数{},请求数{}", uniqueId, day, entity.getDay());
      return false;
    }
    return true;
  }

  /**
   * 两个时间是否超出时间单位 例如start=2022-1-19 9:39:10:000,end=2022-1-19 9:39:11:000
   *
   * 

当TimeUnit.MINUTES时,没超出false,因为相差不到1分钟 * *

当TimeUnit.SECONDS时,超出true,因为相差超过1秒钟 * * @param start startTime * @param end endTime * @param unit 当TimeUnit * @return boolean */ private static boolean beyond(LocalDateTime start, LocalDateTime end, TimeUnit unit) { Duration duration = Duration.between(start, end); if (TimeUnit.DAYS.equals(unit)) { return duration.toDays() > 0; } else if (TimeUnit.HOURS.equals(unit)) { return duration.toHours() > 0; } else if (TimeUnit.MINUTES.equals(unit)) { return duration.toMinutes() > 0; } else if (TimeUnit.SECONDS.equals(unit)) { return duration.toMillis() > 999; } // 判断不常用 else if (TimeUnit.MILLISECONDS.equals(unit)) { return duration.toMillis() > 0; } throw new IllegalArgumentException("not support timeUnit:" + unit.toString()); } /** * 获取请求者唯一标识,获取用户id,若id为空则获取ip+ua * * @param global 是否全局,全局则只取requestURI * @return 返回md5 */ public static String getUniqueId(boolean global) { HttpServletRequest request = HttpServletUtil.getHttpRequest(); if (request == null) { throw new IllegalArgumentException("请求不合法"); } if (StrUtil.isBlank(request.getRequestURI())) { throw new IllegalArgumentException("请求不合法"); } if (global) { return base64Encoder.encodeToString(request.getRequestURI().getBytes(StandardCharsets.UTF_8)); } String ip = IpUtil.getIp(request); String ua = request.getHeader("User-Agent"); if (StrUtil.isBlank(ip)) { ip = request.getSession().getId(); } if (StrUtil.isBlank(ua)) { ua = "Mozilla/9.9 (Macintosh; Intel Mac OS X 12_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.44"; } return base64Encoder.encodeToString( (request.getRequestURI() + StrUtil.AT + ip + StrUtil.AT + ua) .getBytes(StandardCharsets.UTF_8)); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy