记一次博客被恶意刷留言处理方式

其他 专栏收录该内容
2 篇文章 0 订阅

目录

 

前言:

【0】创建Springboot工程

【1】自定义一个注解

【2】自定义一个拦截器

【3】将拦截器注册到容器中

【4】测试


前言:

博客被恶意刷留言了,导致短时间内无法正常访问,并让我博客的留言板看起来比较糟,本以为攻击者只是一时兴起,看我有开放接口,就攻击测试一下,可第二天博客又受到了攻击,第三天还是如此,看样子是被盯上了,更可恶的是还利用留言回复自动发邮件功能,留下一个公司的邮箱地址,导致通过我的博客作死的给那个公司邮箱回复邮件(好像是狂神公司的邮箱地址,实在是抱歉)。哎,林子大了什么鸟都有,也见惯不怪,毕竟能做这种事的人心理是有点问题的,估计是小时候有过什么阴影,导致人格扭曲了那么一点,说实话,挺可怜这种人的,悲哀!

博客中留言功能是没有做限制的,初衷就是让所有人都能够在这个平台畅所欲言,不做限制,可这也给了一些人可乘之机,例如上面那位恶意刷留言的,那我们要如何做防护呢,既要做到不受限制的留言,又不能让人恶意刷留言,没错,就是拦截器了,咱们可以指定某个接口在指定的时间内访问的次数受到限制。以一个Springboot工程为例,咱们来讲述一下如何拦截。

【0】创建Springboot工程

使用idea搭建Springboot工程

yml配置文件:

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    timeout: 1800000
    lettuce:
      pool:
        max-active: 20
        max-wait: -1
        max-idle: 5
        min-idle: 0

主要的pom依赖:

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- spring2.X集成redis所需common-pool2-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.6.0</version>
</dependency>
<!-- json解析-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.28</version>
</dependency>

【1】自定义一个注解

我们自定义一个注解,可以将这个注解作用在要拦截接口的方法上,当在接口的方法上加了这个注解后,就可以按照指定的规则进行拦截,如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface AccessLimit {
    int seconds();
    int maxCount();
}

这里注解类上的三个注解称为元注解,其分别代表的含义如下:

  • @Documented:注解信息会被添加到Java文档中
  • @Retention:注解的生命周期,表示注解会被保留到什么阶段,可以选择编译阶段、类加载阶段,或运行阶段
  • @Target:注解作用的位置,ElementType.METHOD表示该注解仅能作用于方法上

在自定义注解类中,定义了两个方法,seconds()、maxCount(),表示指定时间内请求的次数

  • seconds():表示指定的时间内
  • maxCount():表示请求的次数

【2】自定义一个拦截器

  • 通过自定义的注解传递指定时间和请求次数
  • 使用redis记录请求次数
  • 当访问次数达到指定上限的时候进行限制
@Component
public class SessionInterceptor 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();

            String ip=request.getRemoteAddr();
            String key = request.getServletPath() + ":" + ip ;

            // 从redis中获取用户访问的次数
            Integer count = (Integer) redisTemplate.opsForValue().get(key);

            System.out.println(count);

            if (null == count || -1 == count) {
                // 第一次访问
                redisTemplate.opsForValue().set(key, 1,seconds, TimeUnit.SECONDS);
                return true;
            }

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

            // 超出访问次数
            if (count >= maxCount) {
                // response 返回 json 请求过于频繁请稍后再试
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json; charset=utf-8");
                Response result = new Response<>();
                result.setCode("9999");
                result.setMsg("操作过于频繁");
                Object obj = JSONObject.toJSON(result);
                response.getWriter().write(JSONObject.toJSONString(obj));
                return false;
            }
        }

        return true;
    }
}

【3】将拦截器注册到容器中

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private SessionInterceptor sessionInterceptor;
    @Bean
    public SessionInterceptor tokenVerifyInterceptor() {
        return new SessionInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(sessionInterceptor);
        registry.addInterceptor(tokenVerifyInterceptor()).addPathPatterns("/**");
        WebMvcConfigurer.super.addInterceptors(registry);
    }
}

【4】测试

编写controller进行测试

@RestController
public class TestController {
    @GetMapping("test")
    @AccessLimit(seconds = 15, maxCount = 3) //15秒内 允许请求3次
    public String testAccessLimit() {

        return "success";
    }
}

为了方便显示,对返回结果进行处理:

public class Response<T> implements Serializable {
    private static final long serialVersionUID = -4505655308965878999L;

    //请求成功返回码为:0000
    private static final String successCode = "0000";
    //返回数据
    private T data;
    //返回码
    private String code;
    //返回描述
    private String msg;

    public Response(){
        this.code = successCode;
        this.msg = "请求成功";
    }

    public Response(String code,String msg){
        this();
        this.code = code;
        this.msg = msg;
    }
    public Response(String code,String msg,T data){
        this();
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    public Response(T data){
        this();
        this.data = data;
    }

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public static String getSuccessCode() {
        return successCode;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

访问:http://localhost:8080/test,可以看到正常请求和频繁刷新请求的结果:

image-20210124232246874

image-20210124232422974

到这里就差不多了,最后放一下整个工程的目录结构:

image-20210124232612248

这里还是得感谢攻击我博客的那个人,让我对拦截功能更熟悉了

打不倒你的,只会让你更强大!

  • 2
    点赞
  • 1
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值