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次
在這裏插入圖片描述

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