SoFunction
Updated on 2025-04-04

springboot interface service, prevent brushing and request attacks, AOP implementation method

Springboot interface service, prevent brushing and prevent request attacks, AOP implementation

This article uses AOP to prevent the interface service of spring boot from being attacked by network

Add AOP dependency

<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

AOP custom annotation class

package ;

import .*;

/**
  * Notes for anti-brush current limit
  * The default is that it can only be called once within 5 seconds.
  */
@Target({  })
@Retention()
@Documented
public @interface RateLimit {

    /** Current limit key */
    String key() default "limit:";

    /** Period, unit is seconds */
    int cycle() default 5;

    /** Number of requests */
    int count() default 1;

    /** Default prompt message */
    String msg() default "Do not click repeatedly";
}

AOP sectional business category

package ;

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

/**
  * Facet: Realize current limit verification
  */
@Aspect
@Component
public class AccessLimitAspect {

    @Resource
    private RedisTemplate&lt;String, Integer&gt; redisTemplate;

    /**
      * Here we use the form of annotations
      * Of course, we can also directly specify the package that needs to be intercepted, the class and method that needs to be intercepted through point-cut expressions.
      */
    @Pointcut("@annotation()")
    public void limitPointCut() {
    }

    /**
      * Surround notification
      */
    @Around("limitPointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        // Get the annotated method        MethodInvocationProceedingJoinPoint mjp = (MethodInvocationProceedingJoinPoint) pjp;
        MethodSignature signature = (MethodSignature) ();
        Method method = ();

        // Get the annotation on the method        RateLimit rateLimit = ();
        if (rateLimit == null) {
            // If there is no annotation, continue to call without any processing            return ();
        }
        /**
          * The code has come here, and it means that there is a RateLimit annotation, so the current limit verification is needed.
          * 1. Here you can use Redis API for counting and verification
          * 2. You can also use Lua script for counting and verification here, both of which are OK.
          */
        //Get request object        ServletRequestAttributes attributes = (ServletRequestAttributes) ();
        HttpServletRequest request = ();
        // Get the requested IP address        String ip = getIpAddr(request);
        // Request url path        String uri = ();
        // key saved in redis        String key = "RateLimit:" + ip + ":" + uri;
        // There is a key in the cache, and the current interface has been called within the limited access period.        if ((key)) {
            // The number of visits increased by 1            ().increment(key, 1);
            // The number of visits exceeded            if (().get(key) &gt; ()) {
                throw new RuntimeException(());
            }
            // No operation is performed, return true        } else {
            // The first time data is set, the expiration time is the access period determined by the annotation            ().set(key, 1, (), );
        }
        return ();
    }

    //Get the requested home IP address    private String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        try {
            ipAddress = ("x-forwarded-for");
            if (ipAddress == null || () == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = ("Proxy-Client-IP");
            }
            if (ipAddress == null || () == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = ("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || () == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = ();
            }
            // For the case of multiple proxying, the first IP is the real IP of the client, and multiple IPs are divided according to ','            if (ipAddress != null &amp;&amp; () &gt; 15) {
                // = 15
                if ((",") &gt; 0) {
                    ipAddress = (0, (","));
                }
            }
        } catch (Exception e) {
            ipAddress = "";
        }
        return ipAddress;
    }
}

test

package ;
import ;
import ;
import ;
import ;
import ;

/**
  * Test interface
  * @author wujiangbo
  * @date 2022-08-23 18:50
  */
@RestController
@RequestMapping("/test")
public class TestController {

    //Only 2 visits in 4 seconds    @RateLimit(key= "testLimit", count = 2, cycle = 4, msg = "Brother, please wait and swipe your request!")
    @GetMapping("/test001")
    public Result&lt;?&gt; rate() {
        ("Request succeeded");
        return ("The request succeeded!");
    }
}

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.