帮我写一个springboot接口防刷的切面和注解实现
时间: 2023-09-10 09:05:44 浏览: 91
springboot+redis实现网站限流和接口防刷功能.zip
### 回答1:
首先,您需要在 Spring Boot 应用中开启 AOP 支持。这可以在应用的主类上通过添加 `@EnableAspectJAutoProxy` 注解来实现。
然后,您可以创建一个切面类来实现防刷逻辑。切面类中可以包含多个通知方法,每个通知方法都可以使用不同的注解来指定执行时机。例如,您可以使用 `@Before` 注解来在目标方法执行之前执行通知方法。
下面是一个示例切面类,该类使用了 `@Before` 注解来实现防刷逻辑:
```java
@Aspect
@Component
public class AntiBrushAspect {
@Before("@annotation(antiBrush)")
public void doBefore(JoinPoint joinPoint, AntiBrush antiBrush) {
// 获取目标方法的参数
Object[] args = joinPoint.getArgs();
// 执行防刷逻辑
// ...
}
}
```
接下来,您可以创建一个注解类来标记需要进行防刷检查的方法。
```java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AntiBrush {
}
```
最后,在需要进行防刷检查的方法上添加 `@AntiBrush` 注解即可。例如:
```java
@AntiBrush
@GetMapping("/test")
public String test() {
// 省略其他代码
}
```
这样,在请求 `/test` 接口时,切面类的通知方法就会被执行,从而实现防刷功能。
### 回答2:
实现一个Spring Boot接口防刷的切面和注解操作如下:
1. 创建一个自定义注解 `@AccessLimit`,用于标记需要进行接口防刷的方法。
```java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
int limit() default 10; // 设置访问限制次数,默认为10次
int seconds() default 60; // 设置时间窗口,默认为60秒
}
```
2. 创建一个自定义切面类 `AccessLimitAspect`,用于拦截带有 `@AccessLimit` 注解的方法,并进行接口防刷的逻辑判断。
```java
@Aspect
@Component
public class AccessLimitAspect {
@Autowired
private HttpServletRequest request;
@Around("@annotation(accessLimit)")
public Object doAccessLimit(ProceedingJoinPoint joinPoint, AccessLimit accessLimit) throws Throwable {
// 获取请求的 IP 地址和请求路径
String ip = getIpAddress(request);
String url = request.getRequestURL().toString();
// 根据 IP 地址和请求路径限制访问次数
String key = "access:" + ip + ":" + url;
int limit = accessLimit.limit();
int seconds = accessLimit.seconds();
// 设置 Redis 计数器
RedisAtomicInteger counter = new RedisAtomicInteger(key, RedisServerConfig.redisTemplate.getConnectionFactory());
// 定义初始访问次数
if (counter.get() == 0) {
counter.set(1);
counter.expire(seconds, TimeUnit.SECONDS);
} else {
counter.incrementAndGet();
}
// 判断访问次数是否超过限制
if (counter.get() > limit) {
// 超过访问次数限制,抛出自定义异常信息
throw new RuntimeException("请求过于频繁,请稍后再试");
}
// 执行原有方法逻辑
Object result = joinPoint.proceed();
return result;
}
// 获取请求的 IP 地址
public String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个 IP 值,第一个为真实 IP
int index = ip.indexOf(",");
if (index != -1) {
return ip.substring(0, index);
} else {
return ip;
}
}
ip = request.getHeader("X-Real-IP");
if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
return ip;
}
return request.getRemoteAddr();
}
}
```
3. 在需要进行接口防刷的方法上添加 `@AccessLimit` 注解。
```java
@RestController
public class ExampleController {
@AccessLimit(limit = 5, seconds = 60) // 限制访问次数为5次,在60秒时间窗口内
@GetMapping("/example")
public String example() {
return "Success";
}
}
```
通过以上操作,即可实现对指定接口的防刷控制,当超过指定次数时,会抛出自定义异常,可以根据需要进行处理。注意,以上代码还需在Spring Boot启动类上加上 `@EnableAspectJAutoProxy` 注解,以开启AOP自动代理功能。
阅读全文