SpringBoot防止大量請求攻擊的實現

我們使用Jmeter測試同學的網站時,就會出現網站無法訪問,403等錯誤。

An error occurred.

Sorry, the page you are looking for is currently unavailable.

Please try again later.

If you are the system administrator of this resource then you should check the error log for details.

Faithfully yours, nginx.

所以我們需要加上IP訪問時間限制,防止一個IP多次訪問請求,導致整個網站崩潰。

自定義註解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定義註解,用於攔截過於頻繁的請求
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
    int seconds();
    int maxCount();
    boolean needLogin() default true;
}

自定義攔截器:
我采用瞭拋出自定義異常的方式來解決相同IP多次訪問的問題:
throw new DujiaoshouException(20001,"操作過於頻繁");

import com.qykhhr.dujiaoshouservice.exceptionhandler.DujiaoshouException;
import com.qykhhr.dujiaoshouservice.mycomment.AccessLimit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

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

/**
 * 自定義攔截器
 */
@Component
public class AccessLimtInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if (null == accessLimit) {
                return true;
            }
            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            boolean needLogin = accessLimit.needLogin();

            if (needLogin) {
                //判斷是否登錄
            }
            String ip=request.getRemoteAddr();
            String key = request.getServletPath() + ":" + ip ;
            Integer count = (Integer) redisTemplate.opsForValue().get(key);

            if (null == count || -1 == count) {
                redisTemplate.opsForValue().set(key, 1,seconds, TimeUnit.SECONDS);
                return true;
            }

            if (count < maxCount) {
                count = count+1;
                redisTemplate.opsForValue().set(key, count,0);
                return true;
            }

            //  response 返回 json 請求過於頻繁請稍後再試
            throw new DujiaoshouException(20001,"操作過於頻繁");
        }

        return true;
    }
}

在webconfig中配置攔截器

import com.qykhhr.dujiaoshouservice.Interceptor.AccessLimtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * 在webconfig中配置攔截器
 */
@Configuration
public class MyWebMvcConfigurer extends WebMvcConfigurerAdapter {

    @Autowired
    private AccessLimtInterceptor accessLimtInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(accessLimtInterceptor);
        super.addInterceptors(registry);
    }
}

在Controller前面加上註解就可以生效瞭

@RestController
public class AppHomeController {

    @GetMapping("/index")
    @AccessLimit(seconds = 1, maxCount = 3) //1秒內 允許請求3次
    public R getImageList(){
        return R.ok().data("appHome","hahaha");
    }
}

使用python發送100次請求,可以發現請求被攔截瞭多少

在這裡插入圖片描述

對於註解,我們也可以不使用它,但是我們需要在攔截器中寫入固定的參數。

到此這篇關於SpringBoot防止大量請求攻擊的實現的文章就介紹到這瞭,更多相關SpringBoot防止大量請求攻擊內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: