SpringBoot中自定义注解实现控制器访问次数限制实例

今天给大家介绍一下SpringBoot中如何自定义注解实现控制器访问次数限制。

在Web中最经常发生的就是利用恶性URL访问刷爆服务器之类的攻击,今天我就给大家介绍一下如何利用自定义注解实现这类攻击的防御操作。

其实这类问题一般的解决思路就是:在控制器中加入自定义注解实现访问次数限制的功能。

具体的实现过程看下面的例子:

步骤一:先定义一个注解类,下面看代码事例:

package example.controller.limit;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
//最高优先级
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {
  /**
   *
   * 允许访问的次数,默认值MAX_VALUE
   */
  int count() default Integer.MAX_VALUE; 

  /**
   *
   * 时间段,单位为毫秒,默认值一分钟
   */
  long time() default 60000;
}

步骤二:定义一个异常类,用来处理URL攻击时产生的异常问题,下面看代码事例:

package example.controller.exception;
public class RequestLimitException extends Exception {
  private static final long serialVersionUID = 1364225358754654702L; 

  public RequestLimitException() {
    super("HTTP请求超出设定的限制");
  } 

  public RequestLimitException(String message) {
    super(message);
  } 

} 

步骤三:定义一个注解的具体实现类,下面看代码事例:

package example.controller.limit;
import example.controller.exception.RequestLimitException;
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;
import java.util.concurrent.TimeUnit; 

@Aspect
@Component
public class RequestLimitContract {
  private static final Logger logger = LoggerFactory.getLogger("RequestLimitLogger");
  private Map<String, Integer> redisTemplate=new HashMap<String,Integer>();
  @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 task = new TimerTask(){  //创建一个新的计时器任务。
          @Override
          public void run() {
            redisTemplate.remove(key);
          }
        };
        timer.schedule(task, limit.time());
        //安排在指定延迟后执行指定的任务。task : 所要安排的任务。10000 : 执行任务前的延迟时间,单位是毫秒。
      }
      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);
    }
  }
}

步骤四:实现一个控制类,并添加使用注解功能。下面看代码事例:

package example.controller;
import example.controller.limit.RequestLimit;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
@Controller
public class URLController {
  @RequestLimit(count=10,time=5000)
  @RequestMapping("/urltest")
  @ResponseBody
  public String test(HttpServletRequest request, ModelMap modelMap) {
    return "aaa";
  }
} 

其中count指的是规定时间内的访问次数,time指的就是规定时间,单位为毫秒。

这样就实现了在控制器这个层次上面的url拦截了。不过这里有个问题,就是如果想在每一个URL页面上面都进行这样的拦截,这种方法明显是不够的。因为我们不可能在每个控制器上面都加上url拦截的注解,所以这种方法只适合在某些特定的URL拦截上面使用它们。

那如何实现过滤器级别上面的URL访问拦截呢?这里先给大家卖一个关子,我将会在下一节中给大家介绍如何利用过滤器实现URl访问拦截,并且利用JPA实现ip黑名单的功能,加入IP黑名单后就不可以进行任何URL的访问了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 配置Spring4.0注解Cache+Redis缓存的用法

    前言: 目前公司项目在上一个技术架构的处理,已经搭建好了Redis,但redis只用在了做session的管理,然而 后台的对象缓存没有用上 1. redis 和 ehcache的区别: 简单了解了下,个人觉得 从部署上而言,redis更适合分布式部署,ehcache是在每台应用服务器上开辟一块内存做缓存,集群时还得考虑缓存的情况, redis就不需要考虑缓存了.单独部署在一台服务器中(也可以是在某一台应用服务器中) 2. 项目配置(spring mvc+maven+mybaits+redis)

  • 详解Spring注解--@Autowired、@Resource和@Service

    什么是注解 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点: 1.如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大:如果按需求分开.xml文件,那么.xml文件又会非常多.总之这将导致配置文件的可读性与可维护性变得很低 2.在开发中在.java文件和.xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率 为了解决这两个问题,Spring引入了注解,通过"@XXX"的方式,让注解与Java

  • Spring基于注解整合Redis完整实例

    在<Redis之--Spring整合Redis>一文中,向大家介绍了如何将spring与Redis整合起来,但不是基于注解的形式,很多同学都希望能够通过注解的形式来简单的将Spring与Redis整合起来,这样,在使用的时候,只需要在相应的方法上加上注解,便可以使方法轻松的调用Redis的缓存.那么今天就来向大家介绍如何用基于注解的形式来整合Spring与Redis. 一.项目搭建 今天,我们不使用hibernate来操作数据库了,我们今天选择的框架是: Spring4(包括mvc.conte

  • SpringMVC中解决@ResponseBody注解返回中文乱码问题

    昨天在做项目的时候用@ResponseBody注解,发现返回页面上的中文是乱码,解决过程也是让我很郁闷!!!特此记录一些.目前有下面几种解决方案: @RequestMapping的produces方法 第一种解决方案是使用@RequestMapping注解的produces方法.写法如下: 复制代码 代码如下: @RequestMapping(value = "testPersonalValidtor.do",produces = "application/json;char

  • 详解 Spring注解的(List&Map)特殊注入功能

    详解 Spring注解的(List&Map)特殊注入功能 最近接手一个新项目,已经没有原开发人员维护了.项目框架是基于spring boot进行开发.其中有两处Spring的注解花费了大量的时间才弄明白到底是怎么用的,这也涉及到spring注解的一个特殊的注入功能. 首先,看到代码中有直接注入一个List和一个Map的.示例代码如下: @Autowired private List<DemoService> demoServices; @Autowired private Map<

  • spring注解识别一个接口的多个实现类方法

    1.比如有一个接口如下: public interface Filter { public String doFilter(String param); } 2.有如下接口实现类: public class TimeFilter implements Filter { @Override public String doFilter(String param) { return param.replace("aa", "bb"); } }  3.使用方式:在接口实现

  • SpringBoot中自定义注解实现控制器访问次数限制实例

    今天给大家介绍一下SpringBoot中如何自定义注解实现控制器访问次数限制. 在Web中最经常发生的就是利用恶性URL访问刷爆服务器之类的攻击,今天我就给大家介绍一下如何利用自定义注解实现这类攻击的防御操作. 其实这类问题一般的解决思路就是:在控制器中加入自定义注解实现访问次数限制的功能. 具体的实现过程看下面的例子: 步骤一:先定义一个注解类,下面看代码事例: package example.controller.limit; import org.springframework.core.

  • SpringBoot中自定义注解实现参数非空校验的示例

    前言 由于刚写项目不久,在写 web 后台接口时,经常会对前端传入的参数进行一些规则校验,如果入参较少还好,一旦需要校验的参数比较多,那么使用 if 校验会带来大量的重复性工作,并且代码看起来会非常冗余,所以我首先想到能否通过一些手段改进这点,让 Controller 层减少参数校验的冗余代码,提升代码的可阅读性. 经过阅读他人的代码,发现使用 annotation 注解是一个比较方便的手段,SpringBoot 自带的 @RequestParam 注解只会校验请求中该参数是否存在,但是该参数是

  • 详解SpringBoot中自定义和配置拦截器的方法

    目录 1.SpringBoot版本 2.什么是拦截器 3.工作原理 4.拦截器的工作流程 4.1正常流程 4.2中断流程 5.应用场景 6.如何自定义一个拦截器 7.如何使其在Spring Boot中生效 8.实际使用 8.1场景模拟 8.2思路 8.3实现过程 8.4效果体验 9.总结 1.SpringBoot版本 本文基于的Spring Boot的版本是2.6.7 . 2.什么是拦截器 Spring MVC中的拦截器(Interceptor)类似于ServLet中的过滤器(Filter),它

  • SpringBoot使用自定义注解实现权限拦截的示例

    本文介绍了SpringBoot使用自定义注解实现权限拦截的示例,分享给大家,具体如下: HandlerInterceptor(处理器拦截器) 常见使用场景 日志记录: 记录请求信息的日志, 以便进行信息监控, 信息统计, 计算PV(page View)等 性能监控: 权限检查: 通用行为: 使用自定义注解实现权限拦截 首先HandlerInterceptor了解 在HandlerInterceptor中有三个方法: public interface HandlerInterceptor { //

  • Java中自定义注解介绍与使用场景详解

    注解的概念及分类 1.首先我们来看一下什么是注解: 注解就是某种注解类型的一个实例,我们可以用它在某个类上进行标注,这样编译器在编译我们的文件时,会根据我们自己设定的方法来编译类. 2.注解的分类 注解大体上分为三种:标记注解,一般注解,元注解,@Override用于标识,该方法是继承自超类的.这样,当超类的方法修改后,实现类就可以直接看到了.而@Deprecated注解,则是标识当前方法或者类已经不推荐使用,如果用户还是要使用,会生成编译的警告. 本文主要介绍的是关于Java自定义注解,下面话

  • 谈谈Java中自定义注解及使用场景

    Java自定义注解一般使用场景为:自定义注解+拦截器或者AOP,使用自定义注解来自己设计框架,使得代码看起来非常优雅.本文将先从自定义注解的基础概念说起,然后开始实战,写小段代码实现自定义注解+拦截器,自定义注解+AOP. 一. 什么是注解(Annotation) Java注解是什么,以下是引用自维基百科的内容 Java注解又称Java标注,是JDK5.0版本开始支持加入源代码的特殊语法元数据. Java语言中的类.方法.变量.参数和包等都可以被标注.和Javadoc不同,Java标注可以通过反

  • 详解如何在SpringBoot中自定义参数解析器

    目录 前言 1.自定义参数解析器 2.PrincipalMethodArgumentResolver 3.RequestParamMapMethodArgumentResolver 4.小结 前言 在一个 Web 请求中,参数我们无非就是放在地址栏或者请求体中,个别请求可能放在请求头中. 放在地址栏中,我们可以通过如下方式获取参数: String javaboy = request.getParameter("name "); 放在请求体中,如果是 key/value 形式,我们可以通

  • SpringBoot使用自定义注解+AOP+Redis实现接口限流的实例代码

    目录 为什么要限流 限流背景 实现限流 1.引入依赖 2.自定义限流注解 3.限流切面 4.写一个简单的接口进行测试 5.全局异常拦截 6.接口测试 为什么要限流 系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用.为了避免这种情况,我们就需要对接口请求进行限流. 所以,我们可以通过对并发访问请求进行限速或者一个时间窗口内的的请求数量进行限速来保护系统或避免不必要的资源浪费,一旦达到限制速率则可以拒绝服务.排队或等待

  • SpringBoot通过自定义注解与异步来管理日志流程

    目录 一.前言 二.基础环境 1. 导入依赖 2. 编写yml配置 三.数据库设计 四.主要功能 1. 编写注解 2. 业务类型枚举 3. 编写切片 4. ip工具类 5. 事件发布 6. 监听者 五.测试 1. controller 2. service 3. dao 4. 测试 5. 数据库 六.总结 一.前言 我们在企业级的开发中,必不可少的是对日志的记录,实现有很多种方式,常见的就是基于AOP+注解进行保存,同时考虑到程序的流畅和效率,我们可以使用异步进行保存! 二.基础环境 1. 导入

  • 在springboot中使用注解将值注入参数的操作

    后端的许多管理系统需要登陆者的信息,如shiro登陆后,会将登陆者的信息存储在shiro的session,在使用时需要多行代码获取用户信息.可以把获取在shiro中的登陆者信息封装在一个类中,使用时获取.本文主要讲述如何使用注解将值注入参数,shiro的配置请自行百度. 定义注解 新建一个InfoAnnotation.java的注解类,用于注解参数,代码如下: @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) p

随机推荐