spring boot 對某個接口進行次數限制,防刷。簡易版。demo。


一般的項目 如果沒有做防刷 容易被人爆接口 或者就是說沒有做token防刷過濾。

容易被人用正常的token刷接口。有些token非一次性。

用戶登錄之后生成token會有一個過期時間,但一般沒有做頻率檢查,每訪問一次,會延長這個token時間,刷新用戶狀態

另一種就是養號,拿着真實的token,哪怕你是5分鍾 1分鍾。

很多的網站找回密碼的接口是沒有做防刷的,只是檢查token是否正常。

通過驗證碼認證當前用戶,是否為當前用戶。

前幾天,就用多線程刷過一個三方網站的找回密碼。成功改掉密碼。

一般的網站在改密碼的接口都會先查一次此號碼是否已經注冊,相反就可以通過這個接口猜出真實的用戶手機號,

然后多線程調這個接口猜驗證碼,一般為4位,復雜點的為6位。也會有一些項目加了圖形拖拽(第三方)

前端會提交相關信息給第三方平台,分析你是不是正常的用戶動作,直接封IP。

但是用戶體驗差一點,有些網站為了用戶體驗,忽略了網站安全性,看業務上的取舍了。

進入正題:簡易版(demo)

  aop 實現 :

package com.zhouixi.serviceA.aspect;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.swing.text.Keymap;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.zhouixi.serviceA.annotation.LimitKey;

@Component
@Order
@Aspect
public class LimitAspect {

    private Map limitMap = new HashMap();
    
    
    private static final Logger log = LoggerFactory.getLogger(LimitAspect.class);

    @Pointcut("@annotation(limitKey)")
    public void limit(LimitKey limitKey) {
    }

    @Around("limit(limitKey)")
    public Object aroundLog(ProceedingJoinPoint joinpoint,LimitKey limitKey) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinpoint.getSignature();
        int frequency = limitKey.frequency();
        String methodName = limitKey.methodName();
        String paramKey = limitKey.paramKey();
        String url = limitKey.url();
        //入參
        String[] parameterNames = methodSignature.getParameterNames();
        Object[] args = joinpoint.getArgs();
        Object obj = null ;
        
        for(int i = 0 ; i < parameterNames.length;i++) {
            if(parameterNames[i].equals(paramKey)) {
                obj = args[i];
                break;
            }
        }
        
        System.err.println("args : "+Arrays.toString(args));
        System.err.println("keys : "+Arrays.toString(parameterNames));
        
        StringBuffer sb = new StringBuffer();
        sb.append(url).append("/_").append(methodName).append("_").append(paramKey).append("_").append(obj).append("_key");
        if(limitMap.get(sb.toString()) == null ) {
             limitMap.put(sb.toString(),frequency-1);
        } else {
            
             int l = (int) limitMap.get(sb.toString());
             if(l > 0){
                 limitMap.put(sb.toString(), --l);
             } else {
                 throw new Exception ("系統繁忙,請重試");
             }
        }
        //reids 代替map  redis.set(sb.toString(),frequency,limitKey.timeout());
        System.err.println("剩余次數:"+limitMap.get(sb.toString())+"----->----->----->自定義key:"+sb.toString());
        return joinpoint.proceed();
    }

}

 

controller:

    

     注解聲明:

  

  效果圖:

最后一次:

  

 

postman:

  

 

完成。真實生產場景要換成redis 其他nosql

 


免責聲明!

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



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