使用CacheBuilder类 对用户调用接口限制【每日一学】

需求:
上传文件接口限制,限制每位用户十分钟只能上传10次

思路:
要限制用户调用接口的次数,可以使用Java的缓存库实现计数器,记录用户每次访问接口的时间和次数,并在达到限制后拒绝进一步的访问,拦截器可以使用AOP,进行切面拦截。

实现:
使用Google Guava库中的CacheBuilder类创建一个缓存对象。该缓存对象最多可以缓存1000个记录,并在10分钟后自动过期。然后提供一个isLimitExceeded方法,用于检查特定用户是否已超过允许的最大请求数。如果该用户的请求数已经超过了最大请求数,则返回true,否则返回false。在每次请求之后,该代码将用户的请求次数递增,并将其放入缓存中,以便下一次请求时可以访问。

(该代码仅提供了一种基本的限制方式,并且仅在单个应用程序实例中生效。如果需要更高级的限制功能,例如跨多个应用程序实例或服务器的限制,则可能需要使用其他技术,例如分布式缓存或负载均衡器)

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import java.util.concurrent.TimeUnit;

/**
 * @Author lyuf
 * @Date 2023/4/18
 * @Version 1.0
 * @Describe 用于限制用户调用接口次数
 */

public class ApiLimiter {
    private static Cache<String, Integer> cache;

    public ApiLimiter() {
        this.cache = CacheBuilder.newBuilder()
                .maximumSize(1000) // 最多缓存1000个记录
                .expireAfterWrite(10, TimeUnit.MINUTES) // 10分钟后过期
                .build();
    }

    public static boolean isLimitExceeded(String userId, int maxRequests) {
        int count = 0;
        Integer cachedCount = cache.getIfPresent(userId);
        if (cachedCount != null) {
            count = cachedCount;
        }
        if (count >= maxRequests) {
            return true;
        } else {
            count++;
            cache.put(userId, count);
            return false;
        }
    }
}

自定义AOP:


/**
 * @Author lyuf
 * @Date 2023/4/14
 * @Version 1.0
 * @Describe 用于拦截请求AOP
 */

@Component
@Aspect
@Slf4j
public class MyInterceptor {

    @Lazy
    @Resource
    private CommonAPI commonApi;

    @Autowired
    private ISysUserRoleService sysUserRoleService;

    @Pointcut("@annotation(org.jeecg.modules.aop.AspectAnnotation)")
    private void annotationPointCut() {
    }

    @Before("annotationPointCut()")
    public void checkToken(JoinPoint joinPoint) {
        // 获取方法
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        // 获取AspectAnnotation注解
        AspectAnnotation aspectAnnotation = method.getAnnotation(AspectAnnotation.class);
        // 校验用户调用接口次数
        if (aspectAnnotation.checkCount()) {
            // 获取用户角色Id
            SysUser user = getUserRoleInfo();
            String userId = user .getUserId();
            if (StringUtils.isBlank(userId)) {
                log.info("校验未通过...");
                throw new AuthenticationException("用户id获取为空!");
            }
            boolean limitExceeded = ApiLimiter.isLimitExceeded(userId, 10);
            if (limitExceeded) {
                log.info("校验未通过...");
                throw new AuthenticationException("用户调用频率过高,请十分钟后重试!");
            } else {
                log.info("接口次数校验通过");
            }
        }
    }
}

自定义注解:


/**
 * @Author lyuf
 * @Date 2023/4/14 10:39
 * @Version 1.0
 */

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AspectAnnotation {
    boolean checkCount() default false;
}

注解使用:

/**
     * test
     *
     * @param params
     * @return 数据
     */
    @PutMapping("/admin/update")
    @AspectAnnotation(checkCount= true)
    public String updateAdmin(@RequestBody String params) {
        // 业务代码
        return "";
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值