springboot项目中接口防止恶意请求多次

3,765 阅读2分钟

springboot项目中接口防止恶意请求多次

在项目中,接口的暴露在外面,很多人就会恶意多次快速请求,那我们开发的接口和服务器在这样的频率下的话,服务器和数据库很快会奔溃的,那我们该怎么防止接口防刷呢?

采用注解方式

其实也就是spring拦截器来实现。在需要防刷的方法上,加上防刷的注解,拦截器拦截这些注解的方法后,进行接口存储到redis中。当用户多次请求时,我们可以累积他的请求次数,达到了上限,我们就可以给他提示错误信息。

具体实现

写一个注解

@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {

    int seconds();
    int maxCount();
    boolean needLogin()default true;
}

重点是写下面的拦截器

  • `
    @Component
    public class FangshuaInterceptor extends HandlerInterceptorAdapter {
      @Autowired
      private RedisService redisService;
      @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(accessLimit == null){
                  return true;
              }
              int seconds = accessLimit.seconds();
              int maxCount = accessLimit.maxCount();
              boolean login = accessLimit.needLogin();
              String key = request.getRequestURI();
              //如果需要登录
              if(login){
                  //获取登录的session进行判断
                  //.....
                  key+=""+"1";  //这里假设用户是1,项目中是动态获取的userId
              }
              //从redis中获取用户访问的次数
              AccessKey ak = AccessKey.withExpire(seconds);
              Integer count = redisService.get(ak,key,Integer.class);
              if(count == null){
                  //第一次访问
                  redisService.set(ak,key,1);
              }else if(count < maxCount){
                  //加1
                  redisService.incr(ak,key);
              }else{
                  //超出访问次数
                  render(response,CodeMsg.ACCESS_LIMIT_REACHED); //这里的CodeMsg是一个返回参数
                  return false;
              }
          }
          return true;
      }
      private void render(HttpServletResponse response, CodeMsg cm)throws Exception {
          response.setContentType("application/json;charset=UTF-8");
          OutputStream out = response.getOutputStream();
          String str  = JSON.toJSONString(Result.error(cm));
          out.write(str.getBytes("UTF-8"));
          out.flush();
          out.close();
      }
  }
  ```

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private FangshuaInterceptor interceptor;


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

这样实现了具体的逻辑,我们可以在controller中使用这个注解了

@Controller
public class FangshuaController {

    @AccessLimit(seconds=5, maxCount=5, needLogin=true)
    @RequestMapping("/fangshua")
    @ResponseBody
    public Result<String> fangshua(){


        return Result.success("请求成功");

    }

总结

这里采用了注解方式(拦截器),结合redis来存储请求次数,达到上限就不让用户操作。当然,redis有时间限制,到了时间用户可以再次请求接口的。欢迎大家关注我