https://blog.csdn.net/qq_38095094/article/details/78709433 有時候存在着一些惡意訪問的情況,為了阻止這種情況的發生,我們可以寫一個攔截器,當某個IP的訪問在單位時間內超過一定的次數時,將禁止他繼續訪問。 在這里我們使用了SpringBoot搭配注解來使用 除了springboot需要的依賴之外,我們還需要加上Aspect依賴
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
-
<dependency>
-
<groupId>org.springframework</groupId>
-
<artifactId>spring-aspects</artifactId>
-
<version>4.3.10.RELEASE</version>
-
</dependency>
我們可以自定義一個注解,里面填入單位時間長度和單位時間訪問的最大次數
package com.example.web.demo.test;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import java.lang.annotation.*;
/**
-
@Author:高鍵城
-
@time:
-
@Discription: / @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented @Order(Ordered.HIGHEST_PRECEDENCE) public @interface RequestLimit { /*
- 允許訪問的最大次數 */ int count() default Integer.MAX_VALUE;
/**
- 時間段,單位為毫秒,默認值一分鍾 */ long time() default 60000; }
接下來我們要定義一個異常類
package com.example.web.demo.test;
/**
- @Author:高鍵城
- @time:
- @Discription: */
public class RequestLimitException extends Exception {
-
private static final long serialVersionUID = 1364225358754654702L;
-
-
public RequestLimitException(){
-
super("HTTP請求超出設定的限制");
-
}
-
-
public RequestLimitException(String message){
-
super(message);
-
}
}
有了注解之后,我們要對注解實行一些相應的操作
package com.example.web.demo.test;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; import java.util.Timer; import java.util.TimerTask;
/**
- @author Administrator
- @time:
- @Discription: */
@Aspect
@Component
public class RequestLimitContract {
-
private static final Logger logger = LoggerFactory.getLogger("requestLimitLogger");
-
private Map<String , Integer> redisTemplate = new HashMap<>();
-
-
-
public void requestLimit(final JoinPoint joinPoint , RequestLimit limit) throws RequestLimitException {
-
try {
-
Object[] args = joinPoint.getArgs();
-
HttpServletRequest request = null;
-
for (int i = 0; i < args.length; i++) {
-
if (args[i] instanceof HttpServletRequest) {
-
request = (HttpServletRequest) args[i];
-
break;
-
}
-
}
-
if (request == null) {
-
throw new RequestLimitException("方法中缺失HttpServletRequest參數");
-
}
-
String ip = request.getLocalAddr();
-
String url = request.getRequestURL().toString();
-
String key = "req_limit_".concat(url).concat(ip);
-
if (redisTemplate.get(key) == null || redisTemplate.get(key) == 0) {
-
redisTemplate.put(key, 1);
-
} else {
-
redisTemplate.put(key, redisTemplate.get(key) + 1);
-
}
-
int count = redisTemplate.get(key);
-
if (count > 0) {
-
//創建一個定時器
-
Timer timer = new Timer();
-
TimerTask timerTask = new TimerTask() {
-
-
public void run() {
-
redisTemplate.remove(key);
-
}
-
};
-
//這個定時器設定在time規定的時間之后會執行上面的remove方法,也就是說在這個時間后它可以重新訪問
-
timer.schedule(timerTask, limit.time());
-
}
-
if (count > limit.count()) {
-
logger.info( "用戶IP[" + ip + "]訪問地址[" + url + "]超過了限定的次數[" + limit.count() + "]");
-
throw new RequestLimitException();
-
}
-
} catch (RequestLimitException e){
-
throw e;
-
} catch (Exception e){
-
logger.error( "發生異常",e);
-
}
-
}
}
@before 注解代表在請求發送到控制器之前會先來到這里執行相應的內容,within里面的書寫表示寫在控制器上方並且有對應注解的控制器會來到這里。 在獲得ip和對應的url之后將它作為一個key,存放到map中,假如map中已經存在了這個key,那么多產生一個時間處理器,當時間超過注解書寫的單位時間之后又會將這個key從map中移走。 假如訪問的次數超過了限制,將會拋出異常說明訪問次數過多 最后在使用控制器的時候加上對應的注解即可
@Controller
public class testController{
-
-
-
public String test(HttpServletRequest request){
-
return "hello";
-
}
}
小結:值得注意的是實現RequestLimit注解的方法必須有HttpServletRequest參數
轉載於:https://my.oschina.net/u/3843989/blog/1826874