当前位置: 首页 > news >正文

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<>();@Overridepublic 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);}@Overridepublic 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");}@Overridepublic 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")) {//根据网卡取本机配置的IPInetAddress 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() = 15if (ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}}return ipAddress;}}

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

public class MyFilter02 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("(MyFilter02)项目开始时候执行:------->>>init");}@Overridepublic 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");}@Overridepublic 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;@Beanpublic FilterRegistrationBean<MyFilter01> myFilterRegistrationBean01() {FilterRegistrationBean<MyFilter01> bean = new FilterRegistrationBean<>();bean.setFilter(new MyFilter01(whiteIPMap, alwaysIPList));bean.addUrlPatterns("/api/*");bean.setOrder(1);return bean;}@Beanpublic 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

相关文章:

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

JAVA&#xff1a;Filer过滤器 介绍 Java中的Filter也被称为过滤器&#xff0c;它是Servlet技术的一部分&#xff0c;用于在web服务器上拦截请求和响应&#xff0c;以检查或转换其内容。 Filter的urlPatterns可以过滤特定地址http的请求&#xff0c;也可以利用Filter对访问请求…...

FastAPI -- 第三弹(自定义响应、中间件、代理、WebSockets)

路径操作的高级配置 OpenAPI 的 operationId from fastapi import FastAPIapp FastAPI()# 通过 operation_id 参数设置 app.get("/items/", operation_id"some_specific_id_you_define") async def read_items():return [{"item_id": "F…...

网安小贴士(16)网络安全体系

前言 网络安全体系是一个综合性的系统&#xff0c;旨在保护网络系统中的硬件、软件和数据免受未经授权的访问、泄露、破坏或篡改。这个体系涉及多个方面&#xff0c;包括网络安全策略、安全技术和安全管理等。 一、网络安全体系概述 网络安全体系通常包括以下几个关键组成部分…...

UCOSIII 中断管理接口剖析

引言 在实时操作系统中&#xff0c;中断处理是一个非常重要的环节。理解和掌握中断处理流程对提高系统实时性和稳定性至关重要。本文将详细解析uCOS-III内核中的中断管理接口&#xff0c;包括 OSIntEnter() 和 OSIntExit() 函数的流程&#xff0c;并结合流程图对各个步骤进行说…...

windows 11 PC查询连接过的wlan密码

1:管理员打开cmd 2:输入netsh wlan show profiles 3:netsh wlan show profiles Shw2024-5G keyclear 密码关键内容&#xff1a;12345678...

npm install 出现canvas错误

npm install canvas2.8.0 --ignore-scripts只要是&#xff1a;npm ERR! Failed at the XXXX.X.X install script 这种错误 都可以&#xff1a;npm install XXXX.X.X --ignore-scripts进行更改 https://blog.csdn.net/YXWik/article/details/119039561...

Python爬虫入门篇学习记录

免责声明 本文的爬虫知识仅用于合法和合理的数据收集&#xff0c;使用者需遵守相关法律法规及目标网站的爬取规则&#xff0c;尊重数据隐私&#xff0c;合理设置访问频率&#xff0c;不得用于非法目的或侵犯他人权益。因使用网络爬虫产生的任何法律纠纷或损失&#xff0c;由使用…...

怎样对 PostgreSQL 中的慢查询进行分析和优化?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 怎样对 PostgreSQL 中的慢查询进行分析和优化&#xff1f;一、理解慢查询的危害二、找出慢查询&#x…...

Springboot项目远程部署gitee仓库(docker+Jenkins+maven+git)

创建一个Springboot项目&#xff0c;勾选web将该项目创建git本地仓库&#xff0c;再创建远程仓库推送上去 创建TestController RestController RequestMapping("/test") public class TestController { GetMapping("/hello") public String sayHelloJe…...

Chromium CI/CD 之Jenkins实用指南2024- Windows节点开启SSH服务(七)

1.引言 在现代软件开发和持续集成的过程中&#xff0c;自动化部署和远程管理是不可或缺的关键环节。SSH&#xff08;Secure Shell&#xff09;协议以其强大的安全性和灵活性&#xff0c;成为连接和管理远程服务器的首选工具。对于使用Windows虚拟机作为Jenkins从节点的开发者而…...

阿里大数据面试题集锦及参考答案(3万字长文:持续更新)

目录 MapReduce Shuffle为什么要将数据写入环形缓冲区 MapReduce Shuffle为什么容易发生数据倾斜 Hadoop HA当一个Namenode挂掉,会有数据丢失吗 数据倾斜发生的位置 Combiner了解吗? 什么情况下不能用Combiner? Sum、Count、Count(distinct)哪些能用、哪些不能用Comb…...

springboot 配置 spring data redis

1、在pom.xml引入父依赖spring-boot-starter-parent&#xff0c;其中2.7.18是最后一版支持java8的spring <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.18</…...

Numpy基础用法

Numpy基础用法 numpy.all()num.sun() numpy.all() numpy 中的 all() 函数用于测试 NumPy 数组中所有元素是否都满足指定条件。它接受一个 NumPy 数组作为输入&#xff0c;并返回一个布尔值&#xff0c;指示数组中所有元素是否都满足条件。让我们通过具体的代码示例来深入探讨 n…...

设计模式--享元模式

享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过共享大量细粒度的对象来减少内存消耗。这个模式的核心思想是把对象的状态分为内在状态和外在状态&#xff0c;其中内在状态是可以共享的&#xff0c;而外在状态是需要独立维护的。 享…...

可视化剪辑,账号矩阵,视频分发,聚合私信一体化营销工具 源----代码开发部署方案

可视化剪辑&#xff1a; 为了实现可视化剪辑功能&#xff0c;可以使用流行的视频编辑软件或者开发自己的视频编辑工具。其中&#xff0c;通过设计用户友好的界面&#xff0c;用户可以简单地拖拽和放大缩小视频片段&#xff0c;剪辑出满足需求的视频。在开发过程中&#xff0c;可…...

CCF-CSP认证考试 202406-2 矩阵重塑(其二) 100分题解

更多 CSP 认证考试题目题解可以前往&#xff1a;CSP-CCF 认证考试真题题解 原题链接&#xff1a; 202406-2 矩阵重塑&#xff08;其二&#xff09; 时间限制&#xff1a; 1.0 秒 空间限制&#xff1a; 512 MiB 题目背景 矩阵转置操作是将矩阵的行和列交换的过程。在转置过程…...

初阶数据结构的实现1 顺序表和链表

顺序表和链表 1.线性表1.1顺序表1.1.1静态顺序表&#xff08;不去实现&#xff09;1.1.2动态顺序表1.1.2.1 定义程序目标1.1.2.2 设计程序1.1.2.3编写代码1.1.2.3测试和调试代码 1.1.2 顺序表的问题与思考 1.2链表1.2.1链表的概念及结构1.2.1.1 定义程序目标1.2.1.2 设计程序1.…...

破解反爬虫策略 /_guard/auto.js(一) 原理

背景 当用代码或者postman访问一个网站的时候&#xff0c;访问他的任何地址都会返回<script src"/_guard/auto.js"></script>&#xff0c;但是从浏览器中访问显示的页面是正常的&#xff0c;这种就是网站做了反爬虫策略。本文就是带大家来破解这种策略&…...

40.简易频率计(基于等精度测量法)(3)

&#xff08;1&#xff09;BCD8421码&#xff1a;十进制数字转换成BCD8421码的方法 补零&#xff1a;你需要显示多少位数字&#xff0c;就在前面补上四倍的位宽。比如你要显示一个十进制8位的数字&#xff0c;就在前面补上8*432个零。判断&#xff1a;判断补零部分显示的十进制…...

关于Centos停更yum无法使用的解决方案

最近在使用Centos7.9系统时候&#xff0c;发现yum仓库无法进行安装软件包了&#xff0c;官方说2024年6月30日进行停更&#xff0c;停更后无法提供对应的软件服务。 我在使用yum安装包的时候发现确实不能使用官方服务了&#xff1a; CentOS停更的影响 CentOS停止更新之后&#…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

LangFlow技术架构分析

&#x1f527; LangFlow 的可视化技术栈 前端节点编辑器 底层框架&#xff1a;基于 &#xff08;一个现代化的 React 节点绘图库&#xff09; 功能&#xff1a; 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor

1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...

k8s从入门到放弃之Pod的容器探针检测

k8s从入门到放弃之Pod的容器探针检测 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;容器探测是指kubelet对容器执行定期诊断的过程&#xff0c;以确保容器中的应用程序处于预期的状态。这些探测是保障应用健康和高可用性的重要机制。Kubernetes提供了两种种类型…...

C#最佳实践:为何优先使用as或is而非强制转换

C#最佳实践&#xff1a;为何优先使用as或is而非强制转换 在 C# 的编程世界里&#xff0c;类型转换是我们经常会遇到的操作。就像在现实生活中&#xff0c;我们可能需要把不同形状的物品重新整理归类一样&#xff0c;在代码里&#xff0c;我们也常常需要将一个数据类型转换为另…...

02-性能方案设计

需求分析与测试设计 根据具体的性能测试需求&#xff0c;确定测试类型&#xff0c;以及压测的模块(web/mysql/redis/系统整体)前期要与相关人员充分沟通&#xff0c;初步确定压测方案及具体的性能指标QA完成性能测试设计后&#xff0c;需产出测试方案文档发送邮件到项目组&…...