Aspect实现接口调用频率限制

aop 的思想,就是讲方法外到内执行,中间给切成三段,未进入,进入,已退出

背景:

最近在做一个毕业设计,需要发送邮件(发送密码重置验证码),为了避免用户频繁调用邮件发送接口。
前端:将按钮置灰,开启倒计时,倒计时结束恢复按钮可用
由于没有登录,恶意的可能会使用代码去刷接口(在未进入时将其拦截处理
后端:
使用自定义注解+aop 通过用户ip 限制短时间内的访问次数

准备:

自定注解,可以配置多长时间内最多访问多少次
aspect:处理标注了自定义注解的参数,执行相关逻辑。

代码实现

注解:

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestFrequencyLimit {
    //访问时间间隔 默认是60 秒
    int interval() default 60000;

    //访问次数限制
    int count() default 3;//默认interval 时间内最多访问3次
}


aspect:

/**
 * 接口访问频率 限制aop
 */

@Aspect
@Component
@Slf4j
public class RequestFrequencyLimitAop {
    Map<String, RequestRecord> records = new ConcurrentHashMap<>();//由于是单例,需要注意线程安全,当然也可以使用redis 替代
    @Autowired
    HttpServletRequest request;

    @Pointcut("@annotation(top.forethought.orderfoodyoulike.aops.RequestFrequencyLimit)")
    public void requestLimit() {

    }

    @Around("requestLimit() && @annotation(requestFrequencyLimit)")
    public Object doAround(ProceedingJoinPoint joinPoint, RequestFrequencyLimit requestFrequencyLimit) throws Throwable {
        Object res = null;
        long now = System.currentTimeMillis();
        if (isNull(requestFrequencyLimit)) {
            return joinPoint.proceed();
        }
        //根据ip查找访问记录
        String clientIp = IpUtil.getIpAddress(request);
        RequestRecord requestRecord = records.get(clientIp);
        if (isNull(requestRecord) || now - requestRecord.firstRequestTime > requestFrequencyLimit.interval()) {
            requestRecord = new RequestRecord();
            requestRecord.firstRequestTime = now;
            requestRecord.requestCount = 1;
        } else {
            //更新访问次数
            requestRecord.requestCount++;
        }
        if (requestRecord.requestCount > requestFrequencyLimit.count()) {
            log.error("访问太过频繁,请稍后再试,ip={}", clientIp);
            throw GlobalException.builder().msg("访问太过频繁,请稍后再试").build();
        }
        //保存访问记录
        records.put(clientIp, requestRecord);
        return joinPoint.proceed();

    }

    class RequestRecord {
        int requestCount;//访问次数
        Long firstRequestTime;//第一次访问时间

    }
}

使用效果:

在这里插入图片描述
60秒内同一个ip 最多访问该接口3次
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章