xy1110 2018-04-24 03:53 采纳率: 50%
浏览 3020
已采纳

我想采用SpringBoot实现限制ip访问次数,为啥没有效果?

注解类:图片说明
判断方法:
图片说明
限制的接口方法:
图片说明
麻烦大神帮忙看看,知道一下

  • 写回答

2条回答 默认 最新

  • 苏-李 2018-04-24 05:38
    关注

    有时候存在着一些恶意访问的情况,为了阻止这种情况的发生,我们可以写一个拦截器,当某个IP的访问在单位时间内超过一定的次数时,将禁止他继续访问。
    在这里我们使用了SpringBoot搭配注解来使用
    除了springboot需要的依赖之外,我们还需要加上Aspect依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.3.10.RELEASE</version>
    </dependency>
    

    1
    2
    3
    4
    5
    6
    我们可以自定义一个注解,里面填入单位时间长度和单位时间访问的最大次数

    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; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 接下来我们要定义一个异常类

    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);
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      有了注解之后,我们要对注解实行一些相应的操作

      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 redisTemplate = new HashMap<>();

      @Before("within(@org.springframework.stereotype.Controller *) && @annotation(limit)")
      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() {
      @Override
      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);
      }
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      @before 注解代表在请求发送到控制器之前会先来到这里执行相应的内容,within里面的书写表示写在控制器上方并且有对应注解的控制器会来到这里。
      在获得ip和对应的url之后将它作为一个key,存放到map中,假如map中已经存在了这个key,那么多产生一个时间处理器,当时间超过注解书写的单位时间之后又会将这个key从map中移走。
      假如访问的次数超过了限制,将会抛出异常说明访问次数过多
      最后在使用控制器的时候加上对应的注解即可

    @Controller
    public class testController{
    @RequestMapping("/hello")
    @RequestLimit(count=10,time=60000)
    public String test(HttpServletRequest request){
    return "hello";
    }
    }

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 做个有关计算的小程序
  • ¥15 MPI读取tif文件无法正常给各进程分配路径
  • ¥15 如何用MATLAB实现以下三个公式(有相互嵌套)
  • ¥30 关于#算法#的问题:运用EViews第九版本进行一系列计量经济学的时间数列数据回归分析预测问题 求各位帮我解答一下
  • ¥15 setInterval 页面闪烁,怎么解决
  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化