SpringBoot中实现拦截器级别的URl访问过快拦截,并利用JPA实现IP黑名单的功能。

今天给大家介绍一下SpringBoot中实现拦截器级别URl过快访问拦截,并利用JPA实现IP黑名单的功能。

上一节中已经将中已经介绍了在控制器层面上面的URL拦截,这一节则侧重于网站全局式的拦截。就是不管输入什么URL地址都会进行过滤,判断是否存在URL访问过快的情况发生。因为本文会用到前面已经讲过的JPA和拦截器技术,所以接下来就不对JPA和拦截器的实现过程进行认真的讲解了。有需要的朋友可以看我以前写的博客案例。

步骤一:下面先新建一张IP黑名单表,表的结构如下所示:

步骤二:新建一个实体类,并于黑名单表相映射。例子代码如下:

package example.entity;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "blacklist")
public class Blacklist {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "ip", nullable = true, length = 30)
    private String ip;

    @Temporal(TemporalType.TIMESTAMP)
    private Date iptime; // 日期类型,格式:yyyy-MM-dd HH:mm:ss

    public Blacklist() {
    }

    public Blacklist(String ip, Date iptime) {
        this.ip = ip;
        this.iptime = iptime;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Date getIptime() {
        return iptime;
    }

    public void setIptime(Date iptime) {
        this.iptime = iptime;
    }
}

步骤三:新建一个黑名单的数据库操作类,也就是dao类。例子代码如下:

package example.dao;
import example.entity.Blacklist;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
import java.util.List;
@Transactional
@Repository
public interface BlacklistDao extends JpaRepository<Blacklist, Integer> {
    public List<Blacklist> findByIp(String ip);
}

步骤四:新建一个过滤器类,并实现对URL访问过快的拦截,并将那些攻击者的IP加入黑名单中去。例子代码如下:

package example.Interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import example.controller.exception.RequestLimitException;
import example.controller.limit.RequestLimit;
import example.controller.limit.RequestLimitContract;
import example.dao.BlacklistDao;
import example.entity.Blacklist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import java.util.*;
/**
 * 自定义拦截器1
 *
 * @author   林志强(208017534)
 * @myblog    www.wolzq.com
 * @create    2016年9月20日
 */
public class URLInterceptor implements HandlerInterceptor {
    @Autowired
    private BlacklistDao blacklistDao;
    private Map<String, Integer> redisTemplate=new HashMap<String,Integer>();
    private static final Logger logger = LoggerFactory.getLogger("RequestLimitLogger");
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        return true;
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        String ip = request.getLocalAddr();
        List<Blacklist> blackList =blacklistDao.findByIp(ip);
        if(blackList==null || blackList.size()==0){
            urlHandle(request,10000,10);
        }else{
            modelAndView.setViewName("/errorpage/error");
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }

    public void urlHandle(HttpServletRequest request, long limitTime,int limitCount) throws RequestLimitException {
        try{
        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, limitTime);
        }
        if (count > limitCount) {
            addHostHandle(ip);
            throw new RequestLimitException();
        }
    } catch (RequestLimitException e) {
        throw e;
    } catch (Exception e) {
        logger.error("发生异常: ", e);
    }
    }

    public void addHostHandle(String ip){
        Calendar calendar = Calendar.getInstance();
        Date iptime=calendar.getTime();
        Blacklist blacklist=new Blacklist(ip,iptime);
        blacklistDao.save(blacklist);
    }
}

步骤五:在拦截器添加类中加入bean方法,否则JPA不能自动注入成功,因为容器还未加载就已经实现拦截器的功能了。例子代码如下:

package example.configuration;
import example.Interceptor.ErrorInterceptor;
import example.Interceptor.URLInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class MyWebAppConfigurer
        extends WebMvcConfigurerAdapter {
    @Bean
    public HandlerInterceptor getMyInterceptor(){
        return new URLInterceptor();
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则
        // excludePathPatterns 用户排除拦截
        registry.addInterceptor(getMyInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}

步骤六:在html资源文件下面新建一个错误界面,用于黑名单用户的跳转操作。例子代码如下:

<html>
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
</head>
<body>
<h1>您已经被列入黑名单中,请及时和管理员联系,接触黑名单限制。。。。</h1>
</body>
</html>

这样就已经实现了拦截器级别URl访问过快拦截,并利用JPA实现IP黑名单的功能,是不是特别简单呀。

如果大家想要源代码或者对本人有啥异议都可以加我QQ:208017534  欢迎打扰哦!!!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大内老A

ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则

对于Model验证,理想的设计应该是场景驱动的,而不是Model(类型)驱动的,也就是对于同一个Model对象,在不同的使用场景中可能具有不同的验证规则。举个简...

16410
来自专栏晓晨的专栏

快速序列化组件MessagePack介绍

1732
来自专栏JAVA技术站

Eclispe下集成JFinal中jetty包作为开发环境

1.如果是gradle 或是maven项目地址在这,jetty-server包http://maven.oschina.net/index.html#nexu...

782
来自专栏Spark学习技巧

重要 : 优化flink的四种方式

flink这个框架在逐步变为流处理的主流。本文,我们将针对flink性能调优讲四种不同的方法。

1182
来自专栏非著名程序员

你真的会用Retrofit2吗?Retrofit2完全教程

本文注目录: Retrofit入门 Retrofit注解详解 Gson与Converter RxJava与CallAdapter 自定义Converter 自定...

3747
来自专栏糊一笑

几个关于js数组方法reduce的经典片段

以下是个人在工作中收藏总结的一些关于javascript数组方法reduce的相关代码片段,后续遇到其他使用这个函数的场景,将会陆续添加,这里作为备忘。 jav...

3409
来自专栏Hongten

Hibernate 中继承映射之二 每个具体类一个表

在数据库中建立连个表:post_delivery和express_delivery

522
来自专栏Java帮帮-微信公众号-技术文章全总结

Java面试系列17-编程题-读取服务器字符、实现序列化、计数器、1000阶乘、n出列问题等

一,Java的通信编程,编程题(或问答),用JAVA SOCKET编程,读服务器几个字符,再写入本地显示? Server端程序: package test;...

3908
来自专栏学习力

《Java从入门到放弃》JavaSE入门篇:练习——单身狗租赁系统

2054
来自专栏菩提树下的杨过

职责链(Chain of Responsibility)模式在航空货运中的运用实例

设计模式这东西,基本上属于“看懂一瞬间,用会好几年”。只有实际开发中,当某一模式很好的满足了业务需求时,才会有真切的感觉。借用一句《闪电侠》中,绿箭侠教导闪电侠...

2325

扫码关注云+社区