Spring Security的过滤器链

一 简介

我们只要学过Spring Sercurity,就知道这个框架其实是靠多个过滤器来实现。过滤器是servlet规范中的一种组件。我刚学的时候,也会想SpringSecurity就是把多个过滤器直接放入了过滤器链吗?还是说做了其他处理?

二 过滤器

首先我们先复习一下servlet中的过滤器,看下在常见的Spring框架下是如何运行的。

2.1 搭建环境并测试

创建一个springboot项目,目前只需要引入web依赖。

创建3个简单的过滤器
另外两个就是复制该类的,只是将A分别换成了B和C。



public class AFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("--A--");
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void destroy() {
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("a init");
    }
}

创建请求接口



@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/get")
    public String get(){
        System.out.println("get request");
        return "get api";
    }

    @GetMapping("/test")
    public String test(){
        System.out.println("test request");
        return "test api";
    }

}


创建配置类


@Configuration
public class MywebConfig implements WebMvcConfigurer {


    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean AFilterRegist() {
        FilterRegistrationBean frBean = new FilterRegistrationBean();
        frBean.setFilter(new AFilter());
        frBean.addUrlPatterns("/user/test");
        System.out.println("注册 A");
        frBean.setOrder(1);
        return frBean;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean BFilterRegist() {
        FilterRegistrationBean frBean = new FilterRegistrationBean();
        frBean.setFilter(new BFilter());
        frBean.addUrlPatterns("/user/test");
        System.out.println("注册 B");
        frBean.setOrder(2);
        return frBean;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean CFilterRegist() {
        FilterRegistrationBean frBean = new FilterRegistrationBean();
        frBean.setFilter(new CFilter());
        frBean.addUrlPatterns("/user/get");
        System.out.println("注册 C");
        frBean.setOrder(3);
        return frBean;
    }

}

现象
test接口被A、B过滤器拦截
get接口被C过滤器拦截
在这里插入图片描述

2.2 过滤器如何拦截指定路径

先在CFilter中的doFilter方法中打一个断点。

我们看下此时的过滤器链
除了我们自己写的CFilter,还有一些是框架自带的。我们先研究下,为什么A、B过滤器没被加入其中?
在这里插入图片描述
找到初始化过滤器链的代码
在这里插入图片描述

2.3 过滤器链是如何一个一个执行的

在这里插入图片描述

仔细看下过滤器链的doFIlter方法

 public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {

        if( Globals.IS_SECURITY_ENABLED ) {
           //没走这个分支,代码省略了
           ...
        } else {
            internalDoFilter(request,response);
        }
    }

再看internalDoFilter方法
其中在获取filterConfig对象时,还增加了pos的值
在这里插入图片描述

2.4 问题

基本上到这,我们已经大致搞清了过滤器拦截的部分流程。现在还有一个问题:SpringSecurity的过滤器也是直接加在这个过滤器里面的吗?

三 springSecurityFilterChain

现在几乎都是直接使用SpringBoot来构建项目了。SpringBoot帮我们做了很多事情,降低了开发的复杂度。但同时也容易让我们忽略框架中各个组件。

如果是用传统Spring来整合SpringSecurity,我们需要先在web.xml中配置一个过滤器

    <!--SpringSecurity核心过滤器链-->
    <!--springSecurityFilterChain名词不能修改-->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

这时可能会很疑惑?不是好多过滤器吗,怎么就只配了一个呢?

3.1 环境搭建

只要在pom文件中引入SpringSecurity的依赖就好了

然后我们继续请求get接口。并查看此时过滤器中到底几个过滤器
在这里插入图片描述

3.2 探查DelegatingFilterProxy类的初始化方法

构造方法

先在该类的构造方法打上断点
在这里插入图片描述

看上去没什么特殊的

init方法

因为DelegatingFilterProxy是继承了GenericFilterBean抽象了。DelegatingFilterProxy没有重写父类的init方法。也没有特殊的地方。

3.3 DelegatingFilterProxy类的doFilter

在该方法的第一行打上断点

第一次访问时会初始化

之后就不会了
在这里插入图片描述

继续跟踪进入initDelegate方法
在这里插入图片描述

先看下这个过滤器对象(我称为代理过滤器).里面竟然也有一个过滤器链,只是目前只有一个过滤器
在这里插入图片描述

invokeDelegate

在这里插入图片描述

	protected void invokeDelegate(
			Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		delegate.doFilter(request, response, filterChain);
	}

这个代理过滤器到底干了什么?放到第四节说明

四 FilterChainProxy

首先这是一个Filter,然后看名字。可以叫做过滤器链代理(就是第三节的代理过滤器)

4.1 继续查看doFilter方法

在这里插入图片描述

4.2 查看doFilterInternal

在这里插入图片描述
没想到这个FilterChainProxy真的类似过滤器类,获取了多个过滤器

跟进getFilters方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.3 VirtualFilterChain

在这里插入图片描述
VirtualFilterChain是FilterChainProxy的静态内部类,实现了FilterChain接口。这就是SpringSecurity自己的一个过滤器链

关键字段

在这里插入图片描述

查看VirtualFilterChain的doFilter方法

在这里插入图片描述
在这里插入图片描述

SpringSecurity认证通过

这里的认证通过不是说必须要认证。而是指SpringSecurity的所有过滤器都没有抛出异常即可(因为过滤器会对url进行匹配,只有匹配成功才会进行对应的逻辑处理)
在这里插入图片描述

五 小结

上面大体上说明了SpringSecurity的过滤器是加在哪里的?如何工作的?

引用官网上的一张图就是
在这里插入图片描述
至于各个过滤器都干了什么。本文就不展开讨论了

发布了107 篇原创文章 · 获赞 1 · 访问量 3936

猜你喜欢

转载自blog.csdn.net/m0_38060977/article/details/105041032