拦截器魔法:Spring MVC中的防重放守护者

目录

  1. 简介
  2. HandlerInterceptorAdapter vs HandlerInterceptor
  3. 创建一个防重放拦截器
  4. 注册拦截器
  5. 路径模式匹配
  6. 适配器模式的魅力
  7. 总结

简介

在构建安全可靠的Web应用程序时,防止请求重放攻击是一项关键任务。当用户或系统发出的请求被恶意第三方捕获并重复发送给服务器时,就会发生重放攻击。这可能导致不必要的操作被执行,如重复下单、重复支付等。为了保护我们的应用免受此类威胁,我们可以利用Spring MVC框架提供的强大工具——HandlerInterceptor来实现防重放机制。

HandlerInterceptorAdapter vs HandlerInterceptor

当你决定为自己的应用添加自定义拦截逻辑时,可能会面临选择:是继承 HandlerInterceptorAdapter 还是直接实现 HandlerInterceptor 接口?两者之间的差异在于设计哲学和代码的简洁性。

  • HandlerInterceptorAdapter 是一个适配器类,它实现了 HandlerInterceptor 接口,并提供了所有方法的空实现。因此,如果你只需要覆盖部分方法,使用这个适配器可以让你的代码更加简洁。
  • HandlerInterceptor 接口则要求你必须显式地实现接口中定义的所有方法。这种方式虽然可能引入一些冗余代码,但它提供了更高的透明度,因为你清楚地知道有哪些方法需要处理。
  • 总结:extends HandlerInterceptorAdapter 只重写需要的方法即可,implements HandlerInterceptor需要重写所有方法,可能增加代码冗余

创建一个防重放拦截器

为了确保相同的请求不会被多次处理,我们需要在每次接收到POST请求时检查其唯一标识符(例如订单号或时间戳),并与服务器端存储的历史记录进行比较。下面是一个简单的防重放拦截器实现示例,这里我们使用Redis作为存储介质:

@Component
public class AntiReplayInterceptor extends HandlerInterceptorAdapter {

    private static final String REQUEST_ID = "requestId";
    private static final long EXPIRE_TIME_IN_SECONDS = 60 * 5;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if ("POST".equals(request.getMethod()) && 
            request.getRequestURI().startsWith("/inner/public/syncOrder/v1")) {
            
            // 获取请求体中的唯一标识符
            SynYxcRequest orderSyncDto = extractRequestBody(request);
            String requestId = orderSyncDto.getRequestId();
            
            // 检查是否已经处理过该请求ID
            if (redisTemplate.opsForValue().get(requestId) != null) {
                response.setStatus(HttpServletResponse.SC_CONFLICT);
                return false;
            } else {
                // 将请求ID存入Redis,并设置过期时间
                redisTemplate.opsForValue().set(requestId, "processed", EXPIRE_TIME_IN_SECONDS, TimeUnit.SECONDS);
            }
        }

        return true;
    }

    private SynYxcRequest extractRequestBody(HttpServletRequest request) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(request.getReader().lines().collect(Collectors.joining(System.lineSeparator())), SynYxcRequest.class);
    }
}

注册拦截器

有了拦截器之后,我们需要将其注册到Spring MVC配置中,以确保它能够应用于指定的请求路径:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private AntiReplayInterceptor antiReplayInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(antiReplayInterceptor)
                .addPathPatterns("/inner/public/syncOrder/v1");
    }
}

路径模式匹配

如果不指定 .addPathPatterns() 方法,那么拦截器将会默认应用到所有路径。为了避免不必要的性能开销以及潜在的问题,你应该总是明确地定义你要拦截的路径模式。此外,你还可以使用 .excludePathPatterns() 来排除不需要拦截的路径。

适配器模式的魅力

通过使用 HandlerInterceptorAdapter,你可以轻松地只覆盖那些对你重要的方法,而无需关心其他方法。这种设计不仅简化了代码,也提高了可维护性。当然,如果你更喜欢一切都在掌控之中,直接实现 HandlerInterceptor 接口也是一个不错的选择。

总结

通过本文介绍的内容,我们了解了如何利用Spring MVC中的 HandlerInterceptorHandlerInterceptorAdapter 来构建一个高效的防重放拦截器。无论你是追求代码简洁还是完全控制,Spring都提供了灵活的解决方案,帮助你在Web开发的世界里游刃有余。希望这些知识能为你的项目增添一份安全保障,让每一次请求都能得到恰当的处理。

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

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

相关文章

【MySQL】十三,关于MySQL的全文索引

MySQL的全文索引用于搜索文本中的关键字&#xff0c;类似于like查询。 演示 建表 CREATE TABLE demo (id INT(11) NOT NULL,name CHAR(30) NOT NULL,age INT(11) NOT NULL,info VARCHAR(255),primary key(id),fulltext index futxt_idx_info(info) );此表的默认存储引擎为In…

Aloudata 入选 IDC「GenAI+Data」中国市场代表厂商

近期&#xff0c;国际知名技术研究与咨询机构 IDC 发布了《GenAIData 市场趋势分析及最佳实践案例》报告&#xff0c;总结了当前主要市场特点和数据变化影响&#xff0c;并给出技术布局建议&#xff0c;以供市场参考。报告中还绘制了 GenAIData 发展趋势图&#xff0c;从市场需…

NCR+可变电荷块3——NCB/cell绘图1

文献method参考&#xff1a; 蛋白质序列数据从uniprot中获取 https://www.uniprot.org/uniprotkb/P46013/entry https://www.uniprot.org/uniprotkb/P06748/entry、 1&#xff0c;电荷分布计算&#xff1a; Charge distribution was calculated as the sum of the charges …

单片机锂电池电量电压检测

一、引言 &#xff08;一&#xff09;锂电池电量检测的重要性简述 在如今这个科技飞速发展的时代&#xff0c;众多电子设备都依赖锂电池来供电&#xff0c;像我们日常使用的智能手机、平板电脑、笔记本电脑&#xff0c;还有出行必备的电动自行车、电动汽车等等&#xff0c;锂…

支付宝订单码支付

1.订单码支付&#xff0c;首先下载官方网站提供的sdk包到你的项目中。 2.选择控制器复制官方文档的获取二维码相关的代码示例。打开sdk包中v2的index.php文件&#xff0c;这个才是你选择语言的具体代码。 3.引用里面所需要的类文件&#xff0c;文件下载到你的项目中后&#xf…

【HarmonyOS 5.0】第十二篇-ArkUI公共属性(一)

一、公共样式类属性 ArkUI框架提供的基础组件直接或者间接的继承自 CommonMethod &#xff0c; CommonMethod 中定义的属性样式属于公共样式。下面就来学习这些样式 1.1.尺寸设置 宽高设置 设置组件的宽高&#xff0c;缺省时使用组件自身内容的宽高&#xff0c;比如充满父布…

VTK知识学习(27)- 图像基本操作(二)

1、图像类型转换 1&#xff09;vtkImageCast 图像数据类型转换在数字图像处理中会频繁用到。一些常用的图像算子(例如梯度算子)在计算时出于精度的考虑&#xff0c;会将结果存储为float或double类型&#xff0c;但在图像显示时&#xff0c;一般要求图像为 unsigned char 类型,…

Go C编程 第6课 无人机 --- 计算旋转角

旋转的秘密---认识角度 rt、lt命令学习 goc电子课程 一、编程步骤 第一步 第二步 第三步 第四步 二、画“四轴无人机” &#xff08;一&#xff09;、画第一根机轴 &#xff08;二&#xff09;、画第二根机轴 &#xff08;三&#xff09;、画完整的无人机 三、画“多轴无人…

cursor保存更改操作技巧

1. 当我们在agent模式时&#xff0c;要求cursor更改代码时&#xff0c;cursor回答后&#xff0c;就已经更改了代码了&#xff0c;这时候就可以对程序进行编译和测试&#xff0c; 不一定先要点” accept“, 先测试如果没有问题再点“accept”&#xff0c;这样composer就会多一条…

graphRAG+llama3.2的MOOC课程资源问答系统

文章目录 参考代码地址anacondapycharmLLaMA 3传统ragGraphRAG初始化提示词微调 prompt tuning来创建更适应知识库的知识图谱使用语言模型&#xff08;LLM&#xff09;从每个文本块中提取实体、关系和声明。检索 query&#xff08;本地搜索&#xff08;Local Search&#xff09…

一键打断线(根据相交点打断)——CAD c# 二次开发

多条相交线根据交点一键打断&#xff0c;如下图&#xff1a; 部分代码如下: finally namespace IFoxDemo; public class Class1 {[CommandMethod("ddx")]public static void Demo(){//"ifox可以了".Print();Database db HostApplicationServices.Workin…

Websocket客户端从Openai Realtime api Sever只收到部分数据问题分析

目录 背景 分析 解决方案 背景 正常情况下&#xff0c;会从Openai Realtime api Sever收到正常的json数据,但是当返回音频数据时&#xff0c;总会返回非json数据。这是什么问题呢&#xff1f; 分析 期望的完整响应数据如下&#xff1a; {"session": {"inp…

flask后端开发(1):第一个Flask项目

目录 一、Helloworddebug、host、port的配置 一、Helloword 一般是会创建两个文件夹和app.py app.py from flask import FlaskappFlask(__name__)app.route(/) def hello_world():return Hello World!if __name__ __main__:app.run()右键运行这个py文件&#xff0c;消息绑定…

OAuth 2.0

简介 OAuth 是一种开放标准的授权协议或框架&#xff0c;它提供了一种安全的方式&#xff0c;使第三方应用程序能够访问用户在其他服务上的受保护资源&#xff0c;而无需共享用户的凭证&#xff08;如用户名和密码&#xff09;。OAuth 的核心思想是通过“授权令牌”来代替直接…

玩原神学编程-原神时钟

前言 最近喜欢玩原神这种开放世界探索的游戏&#xff08;还有黑神话、古墓丽影等&#xff09;&#xff0c;只能说纳塔版本的boss盾真的厚&#xff0c;萌新的我去打boss&#xff0c;从白天打到黑夜&#xff0c;黑夜再打到白天&#xff08;游戏里面的时间&#xff09;。 闲话结…

【Spring】深入解析 Spring 原理:Bean 的多方面剖析(源码阅读)

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【Java】登神长阶 史诗般的Java成神之路 一、Bean的作用域 在 Java Spring 框架中&#xff0c;Bean 的作用域是一个关键概念&#xff0c;它决定了 Bean 的生命周期和实例化方式&#xff0c;对应用的性…

基于高德地图js api实现掩膜效果 中间矢量 周围卫星图

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>管网服务</title><style>html,body,#ma…

Vue.js组件(6):echarts组件

1 前言 本章主要对常用的echars图表展示进行基本的组件封装。使用该组件前需要在项目中引入echarts。官网&#xff1a;Apache ECharts npm install echarts --save 2 图表组件 2.1 折线图组件 组件属性&#xff1a;chartId&#xff0c;指定图表挂载div的id&#xff0c;注意不…

RCE常见姿势

文章目录 常见漏洞执行函数&#xff1a;1.系统命令执行函数2.代码执行函数 命令拼接符读取文件命令绕过&#xff1a;空格过滤绕过关键字绕过长度过滤绕过无参数命令执行绕过无字母数字绕过利用%0A截断利用回溯绕过利用create_function()代码注入无回显RCE1.反弹shell2.dnslog外…

selenium执行js

JS知识 获取元素 document.getElement 移除属性&#xff1a;removeAttribute("xx") 窗口移动&#xff1a;window.scrollTo(0, document.body.scrollHeight)方法 drivier.execute_script(js)场景&#xff1a; 日期选择框&#xff0c;不能输入&#xff0c;只能设置…