JAVA:Filer过滤器+案例:请求IP访问限制和请求返回值修改

JAVA:Filer过滤器

介绍

Java中的Filter也被称为过滤器,它是Servlet技术的一部分,用于在web服务器上拦截请求和响应,以检查或转换其内容。
Filter的urlPatterns可以过滤特定地址http的请求,也可以利用Filter对访问请求的数据IP做限制。
文档为本人学习java过滤器过程中做的学习记录。

主要用途:

  • 认证过滤:检查用户请求并确定是否合法。
  • 登记日志:记录请求和响应的日志。
  • 改变请求和响应:可以修改请求头和响应头。
  • 数据压缩:在发送大数据前,可以压缩数据。
  • 加密:对请求和响应进行加密和解密。

使用说明

Spring项目中,创建类继承Filter,实现init、doFilter、destroy方法;

  • init:只在项目启动的时候运行,用来做数据的初始化
  • doFilter:数据过滤,每次http请求都会过滤;filterChain.doFilter(request, servletResponse)前面的程序程序是在执行目标程序前执行,后面的程序是在目标程序后执行,若doFilter程序没有执行filterChain.doFilter,请求将会被拦截。
  • destroy:项目结束时运行

多个过滤器执行顺序

注意:SpringBoot项目中,多个过滤器时,@Order + @WebFilter + @ServletComponentScan 是无法实现按顺序执行过滤器的,推荐使用FilterRegistrationBean实现过滤器按照顺序执行。

  • 原因详细分析见:https://blog.csdn.net/Zong_0915/article/details/126747302

案例(使用FilterRegistrationBean限制过滤器执行循序+限制IP+修改请求返回值)

案例:有两个过滤器:MyFilter01和MyFilter02,要求按先执行过滤器MyFilter01,再执行过滤器MyFilter02顺序。
MyFilter01实现对IP的白名单限制(限制127.0.0.1仅可以访问一次),以及请求返回值的更写。
MyFilter02仅用于体现执行顺序。

  • 案例参考地址:
    https://blog.csdn.net/zhanwuguo8346/article/details/120498756

创建过滤器:MyFilter01用于限制访问IP,修改请求返回值;


@Slf4j
public class MyFilter01 implements Filter {

    private Map<String, Integer> whiteIPMap;

    private List<String> alwaysIPList;

    public MyFilter01(Map<String, Integer> whiteIPMap, List<String> alwaysIPList) {
        this.alwaysIPList = alwaysIPList;
        this.whiteIPMap = whiteIPMap;
    }

    private final ObjectMapper objectMapper = new ObjectMapper();

    private static final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("/swagger-resources", "/v3/swagger-login", "/v2/api-docs")));

    private static Map<String, Integer> whiteIpMapDay = new HashMap<>();


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("(MyFilter01)项目开始时候执行:------->>>init");
        System.out.println("(MyFilter01)whiteIPMap:" + whiteIPMap);
        System.out.println("(MyFilter01)alwaysIPList:" + alwaysIPList);
        whiteIpMapDay.putAll(whiteIPMap);

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("(MyFilter01)项目每次http请求时候执行:------->>>doFilter.start");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String ipAddr = getIpAddr(request);
        log.info("PermissionFilter 过滤器,请求ip为:{}", ipAddr);

        String path = request.getRequestURI().substring(request.getContextPath().length()).replaceAll("[/]+$", "");
        boolean contains = ALLOWED_PATHS.contains(path);
        servletResponse.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=utf-8");

        if (alwaysIPList.contains(ipAddr) && contains) {
            filterChain.doFilter(request, servletResponse);
        } else {
            if (whiteIpMapDay.containsKey(ipAddr)) {
                Integer integer = whiteIpMapDay.get(ipAddr);
                if (integer > 0) {
                    if (contains) {
                        filterChain.doFilter(request, servletResponse);
                    } else {
                        whiteIpMapDay.put(ipAddr, (whiteIpMapDay.get(ipAddr) - 1));
                        filterChain.doFilter(request, servletResponse);
                    }
                } else {
                    BaseResponse<Void> baseResponse = new BaseResponse<>();
                    baseResponse.setCode(-1);
                    baseResponse.setMessage("请求被拒绝,本IP:" + ipAddr + "每天只允许调用:" + whiteIPMap.get(ipAddr) + "次!");
                    String response = objectMapper.writeValueAsString(baseResponse);
                    setServletResponseMessage(servletResponse, response);
                }
            } else {
                BaseResponse<Void> baseResponse = new BaseResponse<>();
                baseResponse.setMessage("不支持本IP请求:" + ipAddr);
                baseResponse.setCode(-1);
                String response = objectMapper.writeValueAsString(baseResponse);
                setServletResponseMessage(servletResponse, response);
            }
        }
        System.out.println("(MyFilter01)项目每次http请求时候执行:------->>>doFilter.end");
    }


    @Override
    public void destroy() {
        System.out.println("(MyFilter01)项目结束时候执行:------->>>destroy");
    }

    /**
     * 处理返回是getWriter()还是getOutputStream();
     * getWriter():out对象用于处理字符流数据。
     * getOutputStream():os用于输出字符流数据或者二进制的字节流数据都可以。
     */
    private void setServletResponseMessage(ServletResponse servletResponse, String response) {
        try {
            servletResponse.getWriter().write(response);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (IllegalStateException e) {
            servletResponse.setContentType("text/plain;charset=UTF-8"); // 设置内容类型和编码
            try {
                ServletOutputStream outputStream = servletResponse.getOutputStream();
                outputStream.write(response.getBytes(StandardCharsets.UTF_8)); // 写入字节数组
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = request.getHeader("x-forwarded-for");
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
                //根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
//                ipAddress= inet.getHostAddress();
                ipAddress = "127.0.0.1";
            }
        }
        //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
        if (ipAddress.length() > 15) { //"***.***.***.***".length() = 15
            if (ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }

}

过滤器:MyFilter02仅作日志记录。体现执行顺序

public class MyFilter02 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("(MyFilter02)项目开始时候执行:------->>>init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("(MyFilter02)项目每次http请求时候执行:------->>>doFilter.start");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("(MyFilter02)项目每次http请求时候执行:------->>>doFilter.end");
    }

    @Override
    public void destroy() {
        System.out.println("(MyFilter02)项目结束时候执行:------->>>destroy");
    }

}

application.yml中设置白名单访问次数,一直有权限访问的白名单。
127.0.0.1限制仅可以访问一次。

permission:
  white-ip: '{"127.0.0.1": 1, "192.168.16.30": 2}'
  always-ip: 127.0.0.1,127.0.0.1 

创建配置类:FilterConfig使用@Value读取配置文件值,注册FilterRegistrationBean到Spring容器中,并设置两个过滤器的执行顺序和过滤路径

@Configuration
public class FilterConfig { 

    @Value("#{${permission.white-ip}}")
    private Map<String, Integer> whiteIPMap;

    @Value("#{'${permission.always-ip}'.split(',')}")
    private List<String> alwaysIPList;

    @Bean
    public FilterRegistrationBean<MyFilter01> myFilterRegistrationBean01() {
        FilterRegistrationBean<MyFilter01> bean = new FilterRegistrationBean<>();
        bean.setFilter(new MyFilter01(whiteIPMap, alwaysIPList));
        bean.addUrlPatterns("/api/*");
        bean.setOrder(1);
        return bean;
    }

    @Bean
    public FilterRegistrationBean<MyFilter02> myFilterRegistrationBean02() {
        FilterRegistrationBean<MyFilter02> bean = new FilterRegistrationBean<>();
        bean.setFilter(new MyFilter02());
        bean.addUrlPatterns("/*");
        bean.setOrder(2);
        return bean;
    }
}

程序中用到的BaseResponse类:

@Data
public class BaseResponse<T> implements Serializable {
    private int code;

    private T data;

    private String message;

    private String description;

    public BaseResponse() {
    }

    public BaseResponse(int code, T data, String message, String description) {
        this.code = code;
        this.data = data;
        this.message = message;
        this.description = description;
    }

    public BaseResponse(int code, T data, String message) {
        this(code, data, message, "");
    }

    public BaseResponse(int code, T data) {
        this(code, data, "", "");
    }

    public BaseResponse(ErrorCodeEnum errorCode) {
        this(errorCode.getCode(), null, errorCode.getMessage(), errorCode.getDescription());
    }
}

测试结果:

第一次执行接口ApiPost(127.0.0.1)接口返回:数据正常创建
在这里插入图片描述

第二次执行接口ApiPost(127.0.0.1)接口返回:提示IP只能每天访问一次(这里没有提供更新:MyFilter01.whiteIpMapDay来实现每天可反问一次,可以使用@Schedule每天定时对静态变态做充值)。
在这里插入图片描述

执行日志:可以看出过滤器按照顺序执行
在这里插入图片描述

参考网址

https://blog.csdn.net/zhanwuguo8346/article/details/120498756
https://blog.csdn.net/Zong_0915/article/details/126747302

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/843306.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[数据分析]脑图像处理工具

###############ATTENTION&#xff01;############### 非常需要注意软件适配的操作系统&#xff01;有些仅适用于Linux&#xff0c;可以点进各自软件手册查看详情。 需要自行查看支持的影像模态。 代码库和软件我没有加以区分。 不是专门预处理的博客&#xff01;&#xf…

Richteck立锜科技电源管理芯片简介及器件选择指南

一、电源管理简介 电源管理组件的选择和应用本身的电源输入和输出条件是高度关联的。 输入电源是交流或直流&#xff1f;需求的输出电压比输入电压高或是低&#xff1f;负载电流多大&#xff1f;系统是否对噪讯非常敏感&#xff1f;也许系统需要的是恒流而不是稳压 (例如 LED…

Mac装虚拟机占内存吗 Mac用虚拟机装Windows流畅吗

如今&#xff0c;越来越多的Mac用户选择在他们的设备上安装虚拟机来运行不同的操作系统。其中&#xff0c;最常见的是使用虚拟机在Mac上运行Windows。然而&#xff0c;许多人担心在Mac上装虚拟机会占用大量内存&#xff0c;影响电脑系统性能。此外&#xff0c;有些用户还关心在…

k8s中部署nacos

1 部署nfs # 在k8s的主节点上执行 mkdir -p /appdata/download cd /appdata/download git clone https://github.com/nacos-group/nacos-k8s.git 将nacos部署到middleware的命名空间中 kubectl create namespace middleware cd /appdata/download/nacos-k8s # 创建角色 kub…

图论模型-迪杰斯特拉算法和贝尔曼福特算法★★★★

该博客为个人学习清风建模的学习笔记&#xff0c;部分课程可以在B站&#xff1a;【强烈推荐】清风&#xff1a;数学建模算法、编程和写作培训的视频课程以及Matlab等软件教学_哔哩哔哩_bilibili 目录 ​1图论基础 1.1概念 1.2在线绘图 1.2.1网站 1.2.2MATLAB 1.3无向图的…

ABAP打印WORD的解决方案

客户要求按照固定格式输出到WORD模板中&#xff0c;目前OLE和DOI研究了均不太适合用于这种需求。 cl_docx_document类可以将WORD转化为XML文件&#xff0c;利用替换字符串方法将文档内容进行填充同 时不破坏WORD现有格式。 首先需要将WORD的单元格用各种预定义的字符进行填充…

canvas:矢量点转栅格

案例描述 ArcGIS提供了“点转栅格”的工具,可以将矢量点转换为栅格数据,以下尝试基于canvas绘图技术,实现经纬度矢量点转换为canvas栅格数据,并在Cesium.js三维地图中进行渲染。 原始数据 转出栅格 案例分析 实现的关键点在于:如何将经纬度坐标与canvas画布坐标进…

【Vue3】工程创建及目录说明

【Vue3】工程创建及目录说明 背景简介开发环境开发步骤及源码 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日…

Figma 中文版指南:获取和安装汉化插件

Figma是一种主流的在线团队合作设计工具&#xff0c;也是一种基于 Web 端的设计工具。在当今的设计时代&#xff0c;Figma 的使用满足了每个人的设计需求&#xff0c;不仅可以实现在线编辑&#xff0c;还可以方便日常管理&#xff0c;有效提高工作效率。然而&#xff0c;相信很…

Java查询ES报错 I/O 异常解决方法: Request cannot be executed; I/O reactor status: STOPPED

问题 ES Request cannot be executed; I/O reactor status: STOPPED 报错解决 在使用ES和SpringBoot进行数据检索时&#xff0c;在接口中第一次搜索正常。第二次在搜索时在控制台就会输出Request cannot be executed; I/O reactor status: STOPPED错误 原因 本文错误是因为在使…

51单片机14(独立按键实验)

一、按键介绍 1、按键是一种电子开关&#xff0c;使用的时候&#xff0c;只要轻轻的按下我们的这个按钮&#xff0c;按钮就可以使这个开关导通。 2、当松开这个手的时候&#xff0c;我们的这个开关&#xff0c;就断开开发板上使用的这个按键&#xff0c;它的内部结构&#xff…

用Java手写jvm之实现java -version的效果

写在前面 源码 。 本文来用纯纯的Java代码来实现java -version的效果&#xff0c;就像下面这样&#xff1a; 1&#xff1a;程序 这里输出类似这样的&#xff1a; java version "9" Java(TM) SE Runtime Environment (build 9181) Java HotSpot(TM) 64-Bit Serve…

突破•指针二

听说这是目录哦 复习review❤️野指针&#x1fae7;assert断言&#x1fae7;assert的神奇之处 指针的使用和传址调用&#x1fae7;数组名的理解&#x1fae7;理解整个数组和数组首元素地址的区别 使用指针访问数组&#x1fae7;一维数组传参的本质&#x1fae7;二级指针&#x…

filebeat,kafka,clickhouse,ClickVisual搭建轻量级日志平台

springboot集成链路追踪 springboot版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.3</version><relativePath/> <!-- lookup parent from…

python—爬虫爬取电影页面实例

下面是一个简单的爬虫实例&#xff0c;使用Python的requests库来发送HTTP请求&#xff0c;并使用lxml库来解析HTML页面内容。这个爬虫的目标是抓取一个电影网站&#xff0c;并提取每部电影的主义部分。 首先&#xff0c;确保你已经安装了requests和lxml库。如果没有安装&#x…

HTML零基础自学笔记(上)-7.18

HTML零基础自学笔记&#xff08;上&#xff09; 参考&#xff1a;pink老师一、HTML, Javascript, CSS的关系是什么?二、什么是HTML?1、网页&#xff0c;网站的概念2、THML的基本概念3、THML的骨架标签/基本结构标签 三、HTML标签1、THML标签介绍2、常用标签图像标签&#xff…

数据结构----算法复杂度

1.数据结构前言 数据是杂乱无章的&#xff0c;我们要借助结构将数据管理起来 1.1 数据结构 数据结构(Data Structure)是计算机存储、组织数据的⽅式&#xff0c;指相互之间存在⼀种或多种特定关系的数 据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤&#xff0c;所…

ranger审计日志对接CDH solr

作者&#xff1a;耀灵 一、准备条件 1、已安装完毕ranger-admin 2、已在CDH上部署solr&#xff08;注意在安装solr时更改下solr在zk上的节点信息&#xff09; 二、更改相关配置 1、修改ranger-2.1.0-admin/contrib/solr_for_audit_setup/install.properties SOLR_USERsolr …

科研绘图系列:R语言单细胞聚类气泡图(single cell bubble)

介绍 单细胞的标记基因气泡图是一种用于展示单细胞数据中特定基因表达情况的可视化方法。它通常用于展示细胞亚群中标记基因的表达水平,帮助研究者识别和区分不同的细胞类型。在这种图表中,每个细胞亚群用不同的颜色表示,而基因表达水平则通过气泡的大小来表示,从而直观地…

嵌入式C++、FreeRTOS、MySQL、Spring Boot和MQTT协议:智能零售系统详细流程介绍(代码示例)

项目概述 随着科技的发展&#xff0c;零售行业正经历着一场数字化转型。智能零售系统通过集成嵌入式技术和大数据分析&#xff0c;为商家提供了高效的运营管理工具。该系统的核心目标是提升顾客体验、优化库存管理、降低运营成本以及实现精准营销。 本项目将结合多种技术栈&a…