SpringBoot+redis實現請用戶求頻率限制


生產環境下可以解決的問題:

  1.短信驗證碼請求評率限制(防止抓包短信轟炸)

  2.熱點數據請求評率限制(防止數據庫爆炸)

  

1.創建自定義注解

package com.bysk.base.annotation;

import java.lang.annotation.*;

/**
* @author: zhangyb
* @date:  2020/11/11 13:58
* @Description: 防止表單重復提交 使用這個注解必須要返回Result類型
* @UpdateUser : zhangyb
* @UpdateDate :2020/11/11 13:58
* @UpdateRemark:
*/
@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FormSubmitLimit {
    /**
    * @author: zhangyb
    * @date:  2020/11/11 14:00
    * @Description: 默認兩秒
    * @UpdateUser : zhangyb
    * @UpdateDate :2020/11/11 14:00
    * @UpdateRemark:
    */
    long limitTime() default 2L;
    /**
    * @author: zhangyb
    * @date:  2020/11/11 14:03
    * @Description: 是否需要登錄,默認需要登錄
    * @UpdateUser : zhangyb
    * @UpdateDate :2020/11/11 14:03
    * @UpdateRemark:
    */
    boolean isLogin() default true;
}
View Code

2.AOP實現之定義注解

package com.bysk.admin.common.filter;

import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSONObject;
import com.bysk.base.annotation.FormSubmitLimit;
import com.bysk.base.enums.MsgEnum;
import com.bysk.base.model.Result;
import com.bysk.base.util.MD5Utils;
import com.bysk.base.util.RedisUtils;
import com.bysk.base.util.WebUtils;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author: zhangyb
 * @date:  2020/11/11 14:02
 * @Description: 防止表單重復提交的請求 使用此注解返回類型必須是R    Result
 * @UpdateUser : zhangyb
 * @UpdateDate :2020/11/11 14:02
 * @UpdateRemark:
 */
@Aspect
@Component
public class FormSubmitAspect {
    @Autowired
    RedisUtils redisUtils;
    @Around("@annotation(formSubmitLimit)")
    @SneakyThrows
    public Object doBefore(ProceedingJoinPoint point, FormSubmitLimit formSubmitLimit) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String requestURI = request.getRequestURI();
        if (formSubmitLimit.isLogin()){
            //如果需要登錄redis存儲規則 userid<->請求url_method
            Object o = redisUtils.get(WebUtils.getUser().getId() + "");
            if (o!=null){
                return JSONObject.toJSONString(Result.fail(MsgEnum.OPR_FAST));
            }
            try {
                redisUtils.set(WebUtils.getUser().getId()+"",requestURI,formSubmitLimit.limitTime());
            } catch (NullPointerException e) {
                return Result.fail();
            }
        }else{
            //客戶端IP
            String clientIP = ServletUtil.getClientIP(request);
            //客戶端請求頭的userAgent
            String header = request.getHeader("User-Agent");
            //MD5加密后的值
            String noLoignKey = MD5Utils.encryptBasedDes(clientIP + header);
            Object o = redisUtils.get(noLoignKey);
            if (o!=null){
                return Result.fail(MsgEnum.OPR_FAST);
            }
            //不需要登錄redis存儲規則 ip+user_agent(MD5)<-> 請求url_mthod
            redisUtils.set(noLoignKey,requestURI,formSubmitLimit.limitTime());
        }
        return  point.proceed();
    }
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM