Idée d'implémentation simple de la limite de courant de la méthode d'interface de demande (RateLimiter)

1. Introduction

En se référant à l'hôte Jihai de la station b, implémentez un schéma de limitation de courant d'interface simple basé sur la méthode IP + (granularité), qui peut simplement empêcher les attaques d'interface, restreindre l'accès fréquent d'une adresse IP à une certaine méthode de l'interface, etc., et éviter Dommages au serveur causés par un brossage malveillant de l'interface Fault.

2. Plan de mise en œuvre

  • Il adopte l'idée d'aop à implémenter et restreint toutes les méthodes de la couche contrôleur.
  • Méthode de limitation actuelle : RateLimiter + Cache (Guava), utilisez Cache pour stocker le RateLimiterr correspondant à une certaine "ip+method", et définissez la politique d'expiration.
2.1 Importer le package jar
<!--Guava-->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.1-jre</version>
</dependency>
<!--aop-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.2 Interface d'essai
package com.example.webtest.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Janson
 * @Description 测试接口
 * @Date 2023/7/10
 */
@RestController
@RequestMapping("")
public class RatelimterTest {
    
    
    
    @GetMapping("testGet")
    public String testGet(){
    
    
        return "testGet";
    }
}
2.3 Interface de limitation de courant
package com.example.webtest.around;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * @author Janson
 * @Description 简单接口限流方案
 * @Date 2023/7/10
 */
@Component
@Aspect
public class IpLimiterAspect {
    
    
    
    // 每秒创建一个令牌,令牌越多,每秒支持的请求次数越多。
    private int DEFAULT_LIMITER_COUNT_PER_SECOND = 1;
    // 创建guava缓存,给的过期时间,防止缓存数据量过大
    Cache<String, RateLimiter> limiterCache = CacheBuilder
            .newBuilder()
            .expireAfterAccess(10, TimeUnit.MINUTES)
            .build();
    @Autowired
    private HttpServletRequest httpServletRequest;
    
    /*
    * 匹配路径:* com.example.webtest.web..*.*(..)
    *       1. 第一个 * : 支持任意返回结果;
    *       2. web后面 .. , 表示覆盖web包及其子包,如果是 . ,则中覆盖web包下的接口,不包含web子包接口;
    *       3. 第二个 * :web包及其子包下所以类;
    *       4. 第三个 * : 所有方法;
    *       5. (..) : 表示方法可以支持任意参数。
    * */
    @Around("execution(* com.example.webtest.web..*.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
        // 如果采用了nginx代理,前端在请求时需要在header中写入真实ip: X-Real-IP = ip
        String ip = httpServletRequest.getHeader("X-Real-IP");
        // 没有采用nginx,则直接获取远程主机ip
        String remoteHost = httpServletRequest.getRemoteHost();
        Signature signature = joinPoint.getSignature();
        
        MethodSignature methodSignature = (MethodSignature) signature;
        // 获取类名称
        String name = joinPoint.getTarget().getClass().getName();
        // 获取方法名称
        String name2 = methodSignature.getName();
        String methodName = name + "." + name2;
        // 拼接缓存key
        String recodeKey = ip + "->" + methodName;
        // 尝试从缓存中获取key值为recodeKey 的缓存rateLimiter,如果获取不到,则创建一个rateLimiter
        RateLimiter rateLimiter = limiterCache.get(recodeKey,
                                                   () -> RateLimiter.create(DEFAULT_LIMITER_COUNT_PER_SECOND));
        // 尝试获取令牌,拿不到令牌则禁止访问。
        if (!rateLimiter.tryAcquire()){
    
    
            System.out.println("操作太频繁,限流了");
            return "操作失败";
        }
        return joinPoint.proceed();
    }

}

Ce qui précède implémente une solution simple de limitation de courant d'interface (anti-brosse).Généralement, pour les projets légers, cela peut résoudre le problème de la prévention des attaques d'interface.

おすすめ

転載: blog.csdn.net/qq_42102911/article/details/131632968