<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      接口防刷!利用redisson快速實現自定義限流注解

      問題:
      在日常開發中,一些重要的對外接口,需要加上訪問頻率限制,以免造成資??損失。

      如登錄接口,當用戶使用手機號+驗證碼登錄時,一般我們會生成6位數的隨機驗證碼,并將驗證碼有效期設置為1-3分鐘,如果對登錄接口不加以限制,理論上,通過技術手段,快速重試100000次,即可將驗證碼窮舉出來。

      解決思路:對登錄接口加上限流操作,如限制一分鐘內最多登錄5次,登錄次數過多,就返回失敗提示,或者將賬號鎖定一段時間。

      實現手段:利用redis的有序集合即Sorted Set數據結構,構造一個令牌桶來實施限流。而redisson已經幫我們封裝成了RRateLimiter,通過redisson,即可快速實現我們的目標。

      • 定義一個限流注解

          import org.redisson.api.RateIntervalUnit;
        
          import java.lang.annotation.ElementType;
          import java.lang.annotation.Retention;
          import java.lang.annotation.RetentionPolicy;
          import java.lang.annotation.Target;
        
          @Target(ElementType.METHOD)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface GlobalRateLimiter {
        
          	String key();
        
          	long rate();
        
          	long rateInterval() default 1L;
        
          	RateIntervalUnit rateIntervalUnit() default RateIntervalUnit.SECONDS;
        
          }
        
      • 利用aop進行切面

          import com.zj.demoshow.annotion.GlobalRateLimiter;
          import lombok.extern.slf4j.Slf4j;
          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.redisson.Redisson;
          import org.redisson.api.RRateLimiter;
          import org.redisson.api.RateIntervalUnit;
          import org.redisson.api.RateType;
          import org.springframework.beans.factory.annotation.Value;
          import org.springframework.core.DefaultParameterNameDiscoverer;
          import org.springframework.expression.Expression;
          import org.springframework.expression.ExpressionParser;
          import org.springframework.expression.spel.standard.SpelExpressionParser;
          import org.springframework.expression.spel.support.StandardEvaluationContext;
          import org.springframework.stereotype.Component;
        
          import javax.annotation.Resource;
          import java.lang.reflect.Method;
          import java.util.concurrent.TimeUnit;
        
          @Aspect
          @Component
          @Slf4j
          public class GlobalRateLimiterAspect {
        
          	@Resource
          	private Redisson redisson;
          	@Value("${spring.application.name}")
          	private String applicationName;
          	private final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
        
          	@Pointcut(value = "@annotation(com.zj.demoshow.annotion.GlobalRateLimiter)")
          	public void cut() {
          	}
        
          	@Around(value = "cut()")
          	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
          		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
          		Method method = methodSignature.getMethod();
          		String className = method.getDeclaringClass().getName();
          		String methodName = method.getName();
          		GlobalRateLimiter globalRateLimiter = method.getDeclaredAnnotation(GlobalRateLimiter.class);
          		Object[] params = joinPoint.getArgs();
          		long rate = globalRateLimiter.rate();
          		String key = globalRateLimiter.key();
          		long rateInterval = globalRateLimiter.rateInterval();
          		RateIntervalUnit rateIntervalUnit = globalRateLimiter.rateIntervalUnit();
          		if (key.contains("#")) {
          			ExpressionParser parser = new SpelExpressionParser();
          			StandardEvaluationContext ctx = new StandardEvaluationContext();
          			String[] parameterNames = discoverer.getParameterNames(method);
          			if (parameterNames != null) {
          				for (int i = 0; i < parameterNames.length; i++) {
          					ctx.setVariable(parameterNames[i], params[i]);
          				}
          			}
          			Expression expression = parser.parseExpression(key);
          			Object value = expression.getValue(ctx);
          			if (value == null) {
          				throw new RuntimeException("key無效");
          			}
          			key = value.toString();
          		}
          		key = applicationName + "_" + className + "_" + methodName + "_" + key;
          		log.info("設置限流鎖key={}", key);
          		RRateLimiter rateLimiter = this.redisson.getRateLimiter(key);
          		if (!rateLimiter.isExists()) {
          			log.info("設置流量,rate={},rateInterval={},rateIntervalUnit={}", rate, rateInterval, rateIntervalUnit);
          			rateLimiter.trySetRate(RateType.OVERALL, rate, rateInterval, rateIntervalUnit);
          			//設置一個過期時間,避免key一直存在浪費內存,這里設置為延長5分鐘
          			long millis = rateIntervalUnit.toMillis(rateInterval);
          			this.redisson.getBucket(key).expire(Long.sum(5 * 1000 * 60, millis), TimeUnit.MILLISECONDS);
          		}
          		boolean acquire = rateLimiter.tryAcquire(1);
          		if (!acquire) {
          			//這里直接拋出了異常  也可以拋出自定義異常,通過全局異常處理器攔截進行一些其他邏輯的處理
          			throw new RuntimeException("請求頻率過高,此操作已被限制");
          		}
          		return joinPoint.proceed();
          	}
          }
        

      ok,通過以上兩步,即可完成我們的限流注解了,下面通過一個接口驗證下效果。

      新建一個controller,寫一個模擬登錄的方法。

      @RestController
      @RequestMapping(value = "/user")
      public class UserController {
      
      
      	@PostMapping(value = "/testForLogin")
      	//以account為鎖的key,限制每分鐘最多登錄5次
      	@GlobalRateLimiter(key = "#params.account", rate = 5, rateInterval = 60)
      	R<Object> testForLogin(@RequestBody @Validated LoginParams params) {
      		//登錄邏輯
      		return R.success("登錄成功");
      	}
      }
      

      啟動服務,通過postman訪問此接口進行驗證。
      image

      posted @ 2024-07-18 20:13  二價亞鐵  閱讀(739)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 风韵丰满熟妇啪啪区老熟熟女| av天堂久久天堂av| 免费观看欧美猛交视频黑人| 亚洲精品乱码久久久久久按摩高清| 亚洲精品日韩在线观看| 一本久道久久综合中文字幕| 91亚洲国产三上悠亚在线播放| 日韩av综合中文字幕| 资源在线观看视频一区二区| 毛多水多高潮高清视频 | 日韩乱码卡一卡2卡三卡四| 永久免费av无码网站直播| 亚洲精品无码成人A片九色播放 | 大尺度国产一区二区视频| 亚洲国产中文字幕在线视频综合| 中文字幕在线无码一区二区三区| 热99久久这里只有精品| 久久精品国产免费观看频道| 99人体免费视频| 精品无码国产日韩制服丝袜| 久久精品国产亚洲av品| 91亚洲国产三上悠亚在线播放| 国内精品自产拍在线播放| 国产高清一区二区不卡| 武定县| 国产成人高清精品免费软件| 在线高清免费不卡全码| 亚洲一区二区精品动漫| 国产老熟女一区二区三区| 国产亚洲av嫩草久久| 午夜福利yw在线观看2020| 亚洲国产超清无码专区| 精品无码一区二区三区在线| 亚洲国产午夜精品理论片| 99久久久无码国产精品动漫| 精品偷拍一区二区三区在| 国产va在线观看免费| 99久久精品国产一区二区| 在线涩涩免费观看国产精品| 欧美亚洲国产日韩一区二区| 国产不卡一区二区在线视频|