SpringSecurity安全过滤器工作原理

news2024/9/17 7:49:55

前面通过三篇文章,从底层代码的角度分析了SpringSecurity的初始化过程。

接下来我们就要具体看一下,Spring Security的安全过滤器初始化、装配好之后,到底是怎么工作的。

还是按图索骥


 

下面我们简单从底层源码分析一下,请求是怎么调用到Spring Security的安全过滤器的。
#### Spring Security安全过滤器工作原理
前面文章已经分析过DelegatinFilterProxy调用到FilterChainProxy的源码,所以我们今天直接从FilterChainProxy的doFilter方法开始:
```
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
        if (!clearContext) {
            doFilterInternal(request, response, chain);
            return;
        }
        try {
            request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
            doFilterInternal(request, response, chain);
        }
        catch (RequestRejectedException ex) {
            this.requestRejectedHandler.handle((HttpServletRequest) request, (HttpServletResponse) response, ex);
        }
        finally {
            SecurityContextHolder.clearContext();
            request.removeAttribute(FILTER_APPLIED);
        }
    }
```

直接看doInternalFilter方法。首先调用getFilters方法:
```
private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest) request);
        HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse) response);
        List<Filter> filters = getFilters(firewallRequest);
        //省略部分源码
        VirtualFilterChain virtualFilterChain = new VirtualFilterChain(firewallRequest, chain, filters);
        virtualFilterChain.doFilter(firewallRequest, firewallResponse);
    }
```
这个getFilters方法的源码就不贴出了,有兴趣的童鞋打开源码看一下,非常简单:从FilterChainProxy持有的DefaultSecurityFilterChain对象中获取到filters,这个filters就是Spring Security初始化过程中装配好的Spring Security的各安全过滤器。

之后用安全过滤器组装一个叫virtualFilterChain的内部对象,这个内部对象主要就是为了持有Spring Security的安全过滤器的,然后通过调用virtualFilterChain的doFilter方法,逐个调用Spring Security的安全过滤器。
#### Spring Security安全过滤器
Spring Security有不少安全过滤器(下图,SprigBoot默认启动的就有15个),我们主要关注与用户身份认证及鉴权密切相关的、或者项目中比较常见的过滤器,其他过滤器暂时略过或一笔带过。
![image.png](/img/bVc4txS)

#### 1.WebAsyncManagerIntegrationFilter
web异步集成过滤器,创建SecurityContextCallableProcessingInterceptor并注册到WebAsyncManager中。

详细作用略。

#### 2.SecurityContextPersistenceFilter
将包含认证信息的SecurityContextHolder在认证之后保存起来(保存在SecurityContextRepository中,一般情况下是session),并且在每次请求发起、认证发生之前从SecurityContextRepository获取出来放置到SecurityContextHolder中。

SecurityContextPersistenceFilter是Spring Security的第2个安全过滤器,在所有认证过滤器之前执行。

SecurityContextPersistenceFilter首先从session中(默认情况下)获取SecurityContext,如果session中没有SecurityContext则创建一个空的SecurityContext,之后将SecurityContext存入SecurityContextHolder。

默认情况下SecurityContextHolder通过ThreadLocalSecurityContextHolderStrategy(也就是使用ThreadLocal)存储SecurityContext。

最后,在请求执行完成之后,将SecurityContextHolder持有的SecurityContext保存起来(默认存储在session中),并清空SecurityContextHolder。

***这样,通过SecurityContextPersistenceFilter过滤器,Spring Security就可以在其他安全过滤器执行之前,从session中获取当前用户的认证信息,因而在后续用户认证操作执行之前、如果当前用户已经完成了认证、则可以确保能够获取到当前用户的认证信息,因此能够通过后续的用户认证过程!!!***

#### 3.HeaderWirterFilter
写Response头信息以便达到对Http Response的相应控制。

HeaderWirterFilter初始化的时候会注册如下HeadWriter:
![image.png](/img/bVc4MXi)
这些HeadWriter会帮助我们对Http Response Header做一些默认设置,比如CacheControlHeadersWriter会执行如下操作:

```
    private static List<Header> createHeaders() {
        List<Header> headers = new ArrayList<>(3);
        headers.add(new Header(CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"));
        headers.add(new Header(PRAGMA, "no-cache"));
        headers.add(new Header(EXPIRES, "0"));
        return headers;
    }
```
一般情况下,我们的应用需要这样的设置,不使用Spring Security的话我们的应用需要手动设置,使用了Spring Security的话,就不需要多此一举了。

#### 4.CsrfFilter
跨域请求过滤器,主要作用是防跨域攻击。

#### 5.LogoutFilter
处理Logout请求,并导航到logout页面。

#### 6.UsernamePasswordAuthenticationFilter
这是Spring Security用户认证的默认实现。

![image.png](/img/bVc4S1M)

他有一个叫AbstractAuthenticationProcessingFilter的父类,doFilter方法就是在父类实现的。

只针对post方法的/login请求生效,所以如果我们要使用该过滤器的话,应用的登录必须是post方法的/login请求。

Spring Security的登录认证过程就是通过这个过滤器实现的,相对还比较复杂,篇幅关系今天就不展开了,今天的主要目标是要搞清楚他的作用。

首先验证当前请求是否需要登录认证,如前所述,如果请求不是post的/login的话,则不做登录认证。

从request中获取的username,password创建UsernamePasswordAuthenticationToken对象进行认证。

认证的过程其实就是我们验证用户名、密码的过程,SpringSecurity有一个默认的用户名、密码认证实现,是在系统启动过程中为用户user生成UUID并打印在控制台、通过用户名user、密码为该UUID完成认证。我们可以实现自己的认证,比如通过数据库的用户名、密码方式完成认证。

认证通过则将认证信息存储在SecurityContext中,如果认证失败(比如用户名密码错误等)则清空SecurityContext并记录相关异常。

#### 7.DefaultLoginPageGeneratingFilter
为/login请求生成登录页面。

#### 8.DefaultLogoutPageGeneratingFilter
导航到登出页面。

#### 9.BasicAuthenticationFilter
对于采用Basic Authentication的请求执行认证。Basi Authentication指的是请求头中包含:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

其中Basic后是采用base64编码的密码信息。

不太了解、没有使用过这种认证方式,略过。

#### 10.RequestCacheAwareFilter
主要作用是缓存当前请求信息,以便在由于认证未通过无法执行该请求的情况下,后续认证通过后重新发起该请求。

#### 11.SecurityContextHolderAwareRequestFilter
用于对request做一层包装,以便支持Servlet中安全相关的API调用。

#### 12.AnonymousAuthenticationFilter
匿名过滤器,从SecurityContextHolder获取认证信息,如果经过了前面的SecurityContextPersistenceFilter、以及UsernamePasswordAuthenticationFilter处理后,SecurityContextHolder中还是没有认证信息的话,说明当前请求并没有通过Spring Security的安全认证,则创建一个匿名认证信息存储在SecurityContextHolder中。

#### 13.SessionManagementFilter
session管理的过滤器,主要为了防止session固化攻击、以及实现登录并发控制功能。

#### 14.ExceptionTranslationFilter
实现异常控制的安全过滤器,注意该过滤器对异常的处理是安全过滤器链执行完成、返回之后。所以,下面的第14个、第15个过滤器执行过程中的异常,也能被本过滤器捕获并处理。

主要处理Spring Security的两类异常:
1. AuthenticationException
2. AccessDeniedException
并将异常交给相应的异常处理器进行处理,比如AccessDeniedException异常处理器通常会通过response返回前端403错误。

#### 15.FilterSecurityInterceptor
Spring Security主要安全过滤器的执行已经接近尾声,但是这个FilterSecurityInterceptor是重头戏。

FilterSecurityInterceptor主要完成如下工作:
1. 解析当前请求的安全配置,主要包括:permitAll、authenticated、denyAll、anonymous等。
2. 从SecurityContextHolder获取安全认证信息。
3. 根据当前请求的安全配置信息及当前用户的安全认证信息进行认证投票,其实就是判断获取到的当前用户的安全认证信息是否符合配置的安全认证需求,符合的话则通过认证,不符合的话抛出accesssdeny异常。

之所以说FilterSecurityInterceptor是Spring Security安全过滤器的重头戏,是因为我们根据项目的具体需求、针对不同请求配置好的安全认证标准的解析是FilterSecurityInterceptor完成的,解析之后检查当前用户是否满足请求所需要的安全要求也是FilterSecurityInterceptor完成的。

如果当前用户认证信息不满足当前请求的安全需求,比如匿名用户访问/helloworld、/helloworld配置为authenticated的话,FilterSecurityInterceptor会抛出accesssdeny异常,最终经ExceptionTranslationFilter处理之后前台页面会收到403错误信息。

#### 总结

Spring security主要安全过滤器的基本工作原理分析完毕,其实每一个安全过滤器的底层工作细节都可以单独写一篇文章进行代码级的分析。但是一般来讲,对于相对复杂一点的知识,入门学习的时候太过细节的分析会影响到对整体框架的理解,Spring Security相对来讲比较负责,因此适合这一原则。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/weixin_44612246/article/details/128357129

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

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

相关文章

英语复习之英语形近词总结(四)

英语形近词总结复习第四部分&#xff1a; 单词 释义例句 genuine 英 /ˈdʒenjuɪn/ 美 /ˈdʒenjuɪn/ adj.真实的&#xff0c;真正的&#xff1b;诚恳的 1.Only genuine refugees can apply for asylum. 只有真正的难民才能申请政治避难。 《牛津词典》 2.This isnt a genui…

Java 区块链应用 | 割韭菜之假如K线涨跌可随意变动修改的实现

大家好&#xff0c;我是程序员大猩猩。 我一直在想&#xff0c;币圈这个行情时涨时跌&#xff0c;不断的割韭菜&#xff0c;不是由市场决定的&#xff01;而是由交易所直接输入一个数值后点击确定按钮而变化的&#xff0c;那么是不是很恐怖的行为。 为了验证这么一个想法&…

十个最适合论文写作的GPTs及其应用

文章目录 一、GPTs让一切皆有可能二、最适合论文写作的GPTs及其应用1、[Paper Search Engine](https://chat.openai.com/g/g-9v5gHG9Bo)2、[Academic Paper Specialist&#xff08;学术论文撰写专家&#xff09;](https://chat.openai.com/g/g-jryw3pfsH)3、[Paper Connect 论文…

day10-Map集合

Map 1.Map 1.1 Map简介 1.为什么使用Map集合 购物车提供的四个商品和购买的数量在后台需要容器存储。 每个商品对象都一一对应一个购买数量。 把商品对象看成是Map集合的键&#xff0c;购买数量看成Map集合的值。 例如: {商品12 , 商品23 &#xff0c; 商品3 2 , 商品4…

msvcp140dll怎么修复,分享5种有效的解决方法

MSVCP140.dll文件丢失这一现象究竟是何缘由&#xff0c;又会引发哪些令人头疼的问题呢&#xff1f;在探索这个问题的答案之前&#xff0c;我们先来深入了解这个神秘的DLL文件。MSVCP140.dll是Microsoft Visual C Redistributable Package的一部分&#xff0c;它扮演着至关重要的…

梦幻西游全新变现,蓝海热门玩法,小白一部手机可操作,日入2000+

亲爱的朋友们&#xff0c;你们好&#xff01;今天我要给大家分享一个热门、可行的网络赚钱项目——梦幻西游全新变现&#xff0c;蓝海热门玩法&#xff0c;小白一部手机可操作&#xff0c;日入2000。 这个项目不需要花冤枉钱&#xff0c;也是我自己实操过的&#xff0c;非常可…

ppt转pdf的java实现

一、实现方式 java采用jacob包的功能&#xff0c;把ppt演示文稿转换为pdf。 支持文件格式&#xff1a;pptx,ppt 二、事先准备 1、依赖于office&#xff0c;需安装office办公软件 2、需要下载一个jacob-1.20-x64.dll的文件&#xff0c;放到java的bin目录下。 文件可以网上搜…

day10-集合

day10 集合 1.集合概述 1.1为什么要用集合&#xff1f; 当我们在实现购物车功能时&#xff0c;可能需要随时添加新商品对象进来&#xff08;个数不确定&#xff09; &#xff0c;也随时可能删除商品对象&#xff0c;这个时候之前学习的数组不满足我们的需求 1.2 什么是集合&…

职称论文的AIGC检测

和高校毕业论文一样&#xff0c;职称论文也是需要通过AIGC检测系统&#xff08;www.checkaigc.com&#xff09;&#xff0c;并且也是有一定的要求的。AIGC检测是因为近年来越来越多人开始使用AI写作工具代写论文&#xff0c;为了防止论文中出现过高的AI论文生成内容&#xff0c…

triton编译学习

一 流程 Triton-MLIR: 从DSL到PTX - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/671434808Superjomns blog | OpenAI/Triton MLIR 迁移工作简介https://superjom

品味Fendi club:精酿啤酒的精致与与众不同

啤酒&#xff0c;作为世界三大饮料之一&#xff0c;其口感和品质的差异能给人们带来截然不同的体验。在众多啤酒中&#xff0c;Fendi club以其与众不同的精酿啤酒风格&#xff0c;吸引了无数热爱啤酒的人。 Fendi club啤酒的精致与与众不同&#xff0c;首先体现在其酿造工艺上。…

pyqt显示指定文件夹的所有文件

pyqt显示指定文件夹的所有文件 目的效果代码 目的 选择文件夹后&#xff0c;显示该文件夹的所有文件。 效果 代码 import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QPushButton, QListView, QFileDialog,QWidget from PyQt5.QtCore import…

【目标检测论文解读复现NO.37】基于改进的 YOLOv8 变电设备红外图像检测

前言 此前出了目标改进算法专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读最新目标检测算法论文&#xff0c…

Vellum for Mac v3.7.2激活版:一键创建,轻松出版

还在为繁琐的电子书制作流程而烦恼吗&#xff1f;Vellum for Mac&#xff0c;让您的电子书创作变得轻松简单&#xff01;支持多种格式导入&#xff0c;自动构建书籍内容&#xff0c;无需担心排版和格式问题。丰富的编辑和排版功能&#xff0c;让您的书籍更加精美。一键导出多种…

element 输入框禁止输入空格以及复制的值进去删除空格(vue自定义指令)开箱即用

实例图&#xff1a; 代码&#xff1a; //输入框禁止输入空格 Vue.directive(noSpace, {bind(el) {//禁止输入空格el.addEventListener("keydown", function (event) {if (event.keyCode 32) {event.preventDefault();}});//复制值时去掉空格el.addEventListener(&q…

MATLAB函数fir1的C语言移值

要移值的matlab函数&#xff1a; h3 fir1(16,[0.25 0.50]); C语言版本 #include <iostream> #include <cmath>#define PI acos(-1)double sincEasy(double *x, int len, int index) {double temp PI * x[index];if (temp 0) {return 1.0; // sinc(0) 1}ret…

十四、Redis Cluster集群

Redis Cluster是Redis提供的一个分布式解决方案&#xff0c;在3.0推出。Redis Cluster可以自动将数据分片分布到不同的master节点上&#xff0c;同时提供了高可用的支持&#xff0c;当某个master节点挂了之后&#xff0c;整个集群还是可以正常工作。1、为什么要用Redis Cluster…

Spring底层入门(十一)

1、条件装配 在上一篇中&#xff0c;我们介绍了Spring&#xff0c;Spring MVC常见类的自动装配&#xff0c;在源码中可见许多以Conditional...开头的注解&#xff1a; Conditional 注解是Spring 框架提供的一种条件化装配的机制&#xff0c;它可以根据特定的条件来控制 Bean 的…

stm32f103c8t6之4x4矩阵按键

基于普中精灵开发板 1、矩阵按键原理 当我们需要使用较多的按键时&#xff0c;单片机的IO口可能不够用,这是就需要使用矩阵按键。 对应IO口如下&#xff1a; 步骤解析&#xff1a; 1、全部按键都没有按下时&#xff0c;全行IO为低电平&#xff08;全列对应的IO设置为下拉低…

1060: 无向图的最大度计算

解法&#xff1a; #include<iostream> #include<vector> using namespace std; int arr[100][100]; int main() {int n, max 0;cin >> n;vector<int> sum(n, 0);for (int i 0; i < n; i) {for (int j 0; j < n; j) {cin >> arr[i][j];…