保卫你的应用:探索过滤器和拦截器的奥秘

news2024/11/25 20:31:17

保卫你的应用:探索过滤器和拦截器的奥秘

  • 前言
  • 概述
  • 实现原理不同
  • 使用范围不同
  • 触发时机不同
  • 注入Bean情况不同
  • springboot中的实现

前言

在现代Web开发中,安全性和性能是至关重要的因素。过滤器和拦截器是Web应用中的两个关键概念,它们可以帮助你保护你的应用免受恶意攻击,同时还可以实现各种功能,从日志记录到性能优化。这两个概念可能听起来有些抽象,但实际上它们就像是你应用的护卫者,站在前线,确保一切都在掌握之中。在本文中,我们将深入探讨过滤器和拦截器的作用、差异以及如何在你的项目中充分利用它们。

概述

拦截器和过滤器都使用了AOP的编程思想,都可以实现诸如日志记录、登录鉴权等功能,但二者的不同点也是比较多的
过滤器(Filters)和拦截器(Interceptors)是在Web开发中用于处理HTTP请求和响应的关键组件,它们用于执行一些特定的任务,如请求预处理、响应处理、日志记录、安全验证等。以下是它们的基本介绍以及在Web开发中的角色:

过滤器(Filters)

  • 基本介绍:过滤器是Servlet规范中的一部分,它是一个可插入的组件,用于在请求进入Servlet容器之前或响应离开容器之后对请求和响应进行预处理或后处理。
  • 角色:过滤器的主要角色是对HTTP请求和响应进行全局性的预处理和后处理。它们可以用于执行以下任务:
    • 认证和授权:验证用户身份并授予权限。
    • 日志记录:记录请求和响应的信息,以便监控和分析。
    • 数据压缩:在服务器端压缩响应数据以减小带宽占用。
    • 编码转换:将请求和响应的字符编码转换为指定的格式。
    • 请求参数处理:对请求参数进行验证、过滤或修改。
    • 缓存控制:管理浏览器缓存,提高性能。

拦截器(Interceptors)

  • 基本介绍:拦截器是在Spring框架中的一部分,它提供了一种机制,允许开发人员在请求处理的不同阶段执行自定义逻辑。
  • 角色:拦截器的主要角色是在Spring框架中对请求和响应进行拦截和处理。它们通常用于以下任务:
    • 权限验证:验证用户是否有权限执行某个操作。
    • 日志记录:记录请求和响应的信息,以进行审计或分析。
    • 性能监测:测量请求处理的性能,检测潜在的性能问题。
    • 异常处理:捕获并处理请求处理中的异常。
    • 国际化:处理多语言支持和区域设置。
    • 缓存控制:管理响应的缓存策略。

区别和选择

  • 过滤器是Servlet规范的一部分,而拦截器是Spring框架的一部分。因此,如果你使用Servlet容器(如Tomcat)来开发Web应用,你可以使用过滤器。如果使用Spring框架,可以选择使用拦截器。
  • 过滤器是全局性的,它们在Servlet容器级别操作,而拦截器是基于Spring MVC框架的,它们在控制器级别操作。
  • 过滤器通常更适用于低级别的任务,如字符编码、缓存控制等。拦截器通常更适合于高级别的任务,如权限验证、日志记录等。
  • 在实际应用中,可以根据任务的性质和框架选择来决定是使用过滤器还是拦截器,有时两者可以结合使用以实现不同层次的处理。

实现原理不同

拦截器和过滤器底层实现方式大不相同,过滤器是基于函数回调的,拦截器则是基于java的反射机制(动态代理)实现的。

我们自定义的过滤器中都会实现一个doFIlter()方法,这个方法有一个FilterChain参数,而实际上它是一个回调接口。Application FilterChain是它的实现类,这个实现类内部也有一个doFilter()方法就是回调方法。

public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

ApplicationFilterChain里面能拿到我们自定义的xxxFilter类,在其内部回调方法doFilter()里面调用各个自定义xxxFilter过滤器,并执行doFilter()方法

public final class ApplicationFilterChain implements FilterChain {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response) {
            ...//省略
            internalDoFilter(request,response);
    }
 
    private void internalDoFilter(ServletRequest request, ServletResponse response){
    if (pos < n) {
            //获取第pos个filter    
            ApplicationFilterConfig filterConfig = filters[pos++];        
            Filter filter = filterConfig.getFilter();
            ...
            filter.doFilter(request, response, this);
        }
    }
 
}

每个xxxFilter会先执行自身的doFilter()过滤逻辑,最后在执行结束前会执行filterChain.doFilter(servletRequest,servletResponse),也就是回调Application FilterChain的doFilter()方法,以此循环执行实现函数回调。

@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        filterChain.doFilter(servletRequest, servletResponse);
    }

使用范围不同

我们看到过滤器实现的是javax.servlet.Filter接口,而这个接口是在servlet规范中定义的,也就是说过滤器Filter的使用要依赖于Tomcat等容器,导致它只能在web程序中用。

而拦截器(Interceptor)它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器。是可以单独使用的。不仅能应用在web程序汇总,也可以用于Application、Swing等程序中。

过滤器(Filters)和拦截器(Interceptors)在使用范围上有一些不同,这取决于它们所属的技术框架以及其执行的阶段和任务。以下是它们的使用范围的不同之处:

过滤器(Filters)的使用范围

  1. Servlet容器级别:过滤器是Servlet规范的一部分,因此它们在Servlet容器级别操作。这意味着它们可以应用于任何基于Servlet的Web应用程序,不依赖于特定的框架。

  2. 低级别任务:过滤器通常用于处理HTTP请求和响应的低级别任务,如字符编码、缓存控制、压缩、请求参数处理等。它们可以修改请求和响应的底层内容。

  3. 全局性处理:过滤器能够对整个Web应用程序的请求和响应进行全局性处理,因此可以应用于多个URL模式下的请求。

拦截器(Interceptors)的使用范围

  1. Spring MVC框架级别:拦截器是Spring MVC框架的一部分,因此它们在Spring应用程序中使用。拦截器只对Spring MVC控制器处理的请求生效。

  2. 高级别任务:拦截器通常用于处理与业务逻辑相关的高级别任务,如权限验证、日志记录、性能监测、国际化、异常处理等。它们更专注于业务逻辑。

  3. 控制器级别处理:拦截器只拦截Spring MVC控制器处理的请求,因此可以根据需要选择性地应用于特定的控制器或URL模式。

总结:

  • 过滤器是Servlet规范的一部分,可用于所有基于Servlet的Web应用程序,用于低级别任务,全局性处理。
  • 拦截器是Spring MVC框架的一部分,仅适用于Spring应用程序,用于高级别任务,控制器级别处理。
  • 选择过滤器或拦截器取决于你的应用程序需求和所使用的技术框架。通常,过滤器用于处理通用的HTTP请求和响应操作,而拦截器用于处理与业务逻辑相关的任务。

触发时机不同

过滤器和拦截器的触发时机也不同,如下图

image-20220403151925186

过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后

拦截器Interceptor是在请求进入servlet后,在进入Controller之前进行预处理的,Controller中渲染了对应的视图之后请求结束。

注入Bean情况不同

在Spring Boot应用程序中,使用过滤器(Filters)和拦截器(Interceptors)时,注入Bean的方式有一些不同,这取决于它们所属的技术框架和生命周期管理。以下是过滤器和拦截器注入Bean的不同之处:

过滤器(Filters)的注入Bean

  1. 过滤器是Servlet规范的一部分,它们通常不是由Spring容器管理的Bean。因此,过滤器的生命周期由Servlet容器管理,而不是Spring容器。

  2. 你不能直接使用Spring的依赖注入(如@Autowired)来注入其他Spring Bean到过滤器中,因为过滤器实例通常不受Spring的控制。

  3. 为了在过滤器中使用Spring的Bean,你可以通过Spring的WebApplicationContextUtils工具类获取ApplicationContext,然后从中获取所需的Bean。

示例代码:

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class MyFilter implements Filter {
    private MyService myService;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        ApplicationContext context = WebApplicationContextUtils
                .getRequiredWebApplicationContext(filterConfig.getServletContext());
        myService = context.getBean(MyService.class);
    }

    // ...
}

拦截器(Interceptors)的注入Bean

  1. 拦截器是Spring MVC框架的一部分,它们通常是由Spring容器管理的Bean。因此,你可以直接使用Spring的依赖注入来注入其他Spring Bean到拦截器中。

  2. 你可以使用@Autowired@Resource等注解将其他Spring Bean注入到拦截器中,这使得在拦截器中使用Spring管理的服务和组件变得非常方便。

示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class MyInterceptor implements HandlerInterceptor {
    private MyService myService;

    @Autowired
    public MyInterceptor(MyService myService) {
        this.myService = myService;
    }

    // ...
}

总结:

  • 过滤器通常不是由Spring容器管理的Bean,因此在过滤器中注入Spring Bean 需要使用WebApplicationContextUtils等方式来手动获取Spring容器中的Bean。
  • 拦截器通常是由Spring容器管理的Bean,因此你可以使用常规的Spring依赖注入方式(如@Autowired)来注入其他Spring Bean 到拦截器中,这更加便捷。

springboot中的实现

理解过滤器和拦截器的差异,让我们以一个基于Spring Boot的用户认证示例为例,展示如何使用过滤器和拦截器来实现用户认证。

场景:我们将创建一个Spring Boot Web应用程序,其中包含一个受保护的资源,只有已登录的用户才能访问。我们将使用过滤器和拦截器分别来实现这个认证逻辑。

项目设置:首先,确保你有一个Spring Boot项目的基础设置。

使用过滤器的示例

  1. 创建一个自定义过滤器类,例如AuthenticationFilter,来检查用户是否已登录。
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

public class AuthenticationFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 在这里检查用户是否已登录,例如从Session中获取用户信息
        // 如果用户未登录,可以重定向到登录页面
        // 如果用户已登录,允许请求继续执行
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化过滤器(可选)
    }

    @Override
    public void destroy() {
        // 销毁过滤器(可选)
    }
}
  1. 在Spring Boot应用程序中注册过滤器。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<AuthenticationFilter> authenticationFilter() {
        FilterRegistrationBean<AuthenticationFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new AuthenticationFilter());
        // 设置需要过滤的URL模式
        registrationBean.addUrlPatterns("/protected/*"); // 这里假设受保护的资源在/protected/下
        return registrationBean;
    }
}

使用拦截器的示例

  1. 创建一个拦截器类,例如AuthenticationInterceptor,来检查用户是否已登录。
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AuthenticationInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 在这里检查用户是否已登录,例如从Session中获取用户信息
        // 如果用户未登录,可以重定向到登录页面
        // 如果用户已登录,返回true允许请求继续执行,或者返回false阻止请求继续执行
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // 请求处理后执行的操作(可选)
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) throws Exception {
        // 完成请求后执行的操作(可选)
    }
}
  1. 在Spring Boot应用程序中注册拦截器。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthenticationInterceptor())
                .addPathPatterns("/protected/**"); // 这里假设受保护的资源在/protected/下
    }
}

在上述示例中,无论你选择使用过滤器还是拦截器,它们都用于拦截请求并执行用户认证逻辑。关于具体的用户认证逻辑(例如如何检查用户是否已登录),需要根据你的应用程序和需求来实现。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软件测试】JUnit详解

文章目录 一. Junit是什么?二.Junit中常见的注解1. Test2. BeforeAll & AfterAll3. BeforeEach & AfterEach4. ParameterizedTest参数化5. Disabled6. Order 三. 测试套件1. 通过class运行测试用例2. 通过包运行测试用例 四. 断言 一. Junit是什么? JUnit是一个用于…

3D打印机升级killpper

本来是想整台新机的&#xff0c;但是想想老机器4max也不能就此放弃&#xff0c;看了看视频&#xff0c;改装升级似乎也没有那么难。然后就是换了喷头、皮带、轴承、挤出机、打印平台、加热板等等。做了干燥箱&#xff0c;改装挤出机结构来适配&#xff0c;风扇口也一并搞掉&…

Astory 访谈|了解「非常律师禹英禑」背后的故事

请先简单做个自我介绍吧&#xff1f; 大家好&#xff0c;我是 Astory 的首席制作人 Younghwa Lee&#xff0c;负责监督《非常律师禹英禑》的制作。很高兴认识你。 是什么启发了你创造了《非常律师禹英禑》系列&#xff1f; 作为制片人&#xff0c;我非常感谢全球粉丝对《非常…

NVIDIA ORIN GPIO

NVIDIA ORIN GPIO 说明 1.Identifying the GPIO Number If you designed your own carrier board, to translate from SOM connector pins to actual GPIO numbers, you must understand the following GPIO mapping formula. The translated GPIO numbers can be controlled …

2023软件测试面试题大全

1.B/S架构和C/S架构区别 B/S 只需要有操作系统和浏览器就行&#xff0c;可以实现跨平台&#xff0c;客户端零维护&#xff0c;维护成本低&#xff0c;但是个性化能力低&#xff0c;响应速度较慢 C/S响应速度快&#xff0c;安全性强&#xff0c;一般应用于局域网中&#xff0c;…

Bootstrap元素的边框样式和设置

目录 01-添加完整边框、上边框、右边框、下边框、左边框02-不要整个边框、上边框、右边框、下边框、左边框03-指定边框的颜色04-设置圆角边框和圆形边框 01-添加完整边框、上边框、右边框、下边框、左边框 示例代码如下&#xff1a; <!DOCTYPE html> <html> <…

关于 Vite 的浅显学习 - 总览

大部分内容来源于vite官网&#xff0c;部分内容来自于 自己测试和总结 Vite 官方中文文档 总览 Vite 是一种新型前端构建工具&#xff0c;能够显著提升前端开发体验。&#xff08;vue 官网打造的&#xff0c;旧一代是 webpack&#xff09; 它主要由两部分组成&#xff1a; 一…

ASPICE标准快速掌握「4.2. 过程能力等级与过程属性」

过程能力等级 0 级:不完整的过程 过程未实施、或未能实现其过程目的。在这个等级只有很少或没有系统化实现过程目的的证据。 过程能力等级 1 级:已执行的过程 已执行的过程实现其过程目的。以下过程属性证明这个等级的实现: PA 1.1 过程实施过程属性 <成就> 过程…

【Redis】Redis中的数据结构和内部编码

Redis中的数据结构和内部编码 type命令实际返回的就是当前键的数据结构类型&#xff0c;它们分别是&#xff1a;string&#xff08;字符串&#xff09;、list&#xff08;列表&#xff09;、hash&#xff08;哈希&#xff09;、set&#xff08;集合&#xff09;、zset&#xf…

文件批量改名:大量文件重命名,不再烦恼

在日常生活和工作中&#xff0c;我们常常会遇到大量的文件需要重命名的情况。例如&#xff0c;整理照片、整理网络下载图片、整理音频和视频文件等等。如果一个一个地手动修改文件名&#xff0c;不仅费时费力&#xff0c;而且容易出错。那么&#xff0c;如何快速高效地批量修改…

Shell 解释器,帮你解析一条Shell语句到底是什么意思

使用Linux系统的朋友&#xff0c;几乎每天都在使用Shell命令&#xff0c;比如 # 新建一个.sh脚本&#xff1a; vim 脚本名.sh # 运行一个.sh脚本&#xff1a; ./脚本名.sh ​​​​​​​Shell语句是一种用于与计算机操作系统交互的文本命令。Shell是计算机操作系统的命令行…

如何在逍遥模拟器上加载Magisk模块

本机环境&#xff1a;win7 64位&#xff0c;Python3.8.10&#xff0c;逍遥模拟器版本9.0.6&#xff0c;安卓版本9&#xff08;手机里的设置-系统-关于平板电脑-Android版本&#xff09;。 已经安装了Magsik&#xff0c;现在需要加载一个新模块。 一、电脑上下载需要安装的模块…

15.(开发工具篇vscode)vscode保存操作后,代码发生变化

问题描述&#xff1a;:visible.sync会自动变成v-model:visible 解决方案&#xff1a; 一&#xff1a;打开设置 二&#xff1a;关键字&#xff08;保存&#xff09;&#xff0c;打开settings.json 三&#xff1a;修改配置项source.fixAll.eslint为false

漏洞复现--Juniper Networks Junos OS EX远程命令执行漏洞(CVE-2023-36845)

免责声明&#xff1a; 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…

学习记录——StyleGAN2+SA-UNet

SA-UNet for Retinal Vessel improvment using StyleGAN2 作者提出了一种改进视网膜图像分割的方法,通过创建图像及其相应的分割地图来实现。作者的解决方案包括使用DRIVE数据集1对StylGAN2进行训练,并使用目前在分割DRIVE图像方面取得最先进结果的SA-UNet模型对新合成的图像…

软件测试面试常常遇到的6大“套路”!

前言 面试中&#xff0c;如何回答HR提出的问题很大程度上决定了面试能不能成功。 下面是软件测试人员在面试过程中经常被问到的6个问题&#xff0c;告诉你怎么回答才不会被面试官套路.. 01、请你做一个自我介绍 误区&#xff1a; 一般人回答这个问题过于平常&#xff0c;只…

(2021|NIPS,VQ-VAE,精度瓶颈松弛,三明治层归一化,CapLoss)CogView:通过转换器掌握文本到图像的生成

CogView: Mastering Text-to-Image Generation via Transformers 公众号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 0. 摘要 通用领域中的文本到图像生成长期以来一直是一个悬而未决的问题&#…

接口测试及常用接口测试工具

首先&#xff0c;什么是接口呢&#xff1f; 接口一般来说有两种&#xff0c;一种是程序内部的接口&#xff0c;一种是系统对外的接口。 系统对外的接口&#xff1a;比如你要从别的网站或服务器上获取资源或信息&#xff0c;别人肯定不会把数据库共享给你&#xff0c;他只能给你…

c语言动态内存分布

前言&#xff1a; 随着我们深入的学习c语言&#xff0c;之前使用的静态内存分配已经难以满足我们的实际需求。比如前面我们的通讯录功能的实现&#xff0c;如果只是静态内存分配&#xff0c;那么也就意味着程序开始的内存分配大小就是固定的&#xff0c;应该开多大的空间呢&am…

重启Oracle数据库命令列表逐步操作

&#x1f495;欢迎来到 Oracle 数据库重启教程&#x1f495; &#x1f3af;第一步&#xff1a;以 oracle 身份登录数据库&#x1f3af; su - oracle &#xff08;如果是WINdows系统的CMD窗口&#xff09;直接从第二步开始&#xff01; &#x1f3af;第二步&#xff1a;进入…