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.