Spring Security架构

文章目录

  • 过滤器回顾
  • DelegatingFilterProxy
  • FilterChainProxy
  • SecurityFilterChain
  • Security Filters
    • 打印Security Filters
    • 将自定义过滤器添加到过滤器链
  • Handling Security Exceptions
  • Saving Requests Between Authentication
    • RequestCache
      • Prevent the Request From Being Saved
    • RequestCacheAwareFilter

Spring Security 是一个提供 身份验证(authentication)授权(authorization)针对常见攻击的保护的框架。凭借对保护 Servlet应用程序Reactive应用程序的一流支持,它成为保护基于 Spring 的应用程序的事实上的标准。

Spring Security is a framework that provides authentication, authorization, and protection against common attacks. With first class support for securing both imperative and reactive applications, it is the de-facto standard for securing Spring-based applications.

本文主要介绍基于 Servlet 的应用程序中 Spring Security 的架构,不涉及基于 Reactive 应用程序的架构。

过滤器回顾

Spring Security 的 Servlet 支持是基于 Servlet Filter 的,因此首先大致了解一下 Filter 的作用是有帮助的。下图显示了单个 HTTP 请求处理的典型分层模型。

filterchain

客户端向应用程序发起请求,Web 容器创建一个 FilterChain,其中包含 Filter 实例和处理 HttpServletRequestServlet 的实例。在Spring MVC 应用程序中,这样的 ServletDispatcherServlet 实例。最多,一个 Servlet 可以处理一个 HttpServletRequestHttpServletResponse。但是,可以使用多个 Filter 用作:

  • 阻止下游 Filter 实例或 Servlet 实例被调用。在这种情况下, Filter 通常只处理 HttpServletResponse
  • 修改下游 Filter 实例和 Servlet 实例使用的 HttpServletRequestHttpServletResponse

Filter 的力量来自传递给它的 FilterChain

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {// do something before the rest of the applicationchain.doFilter(request, response); // invoke the rest of the application// do something after the rest of the application
}

Servlet 和 Filter 的基础知识

2021 07 27 13 14 47

由于 Filter 只影响下游的 Filter 实例和 Servlet 实例,因此调用每个 Filter 实例的顺序非常重要。

DelegatingFilterProxy

Spring提供了一个名为 DelegatingFilterProxyFilter 实现,它允许在Servlet容器的生命周期和Spring的 ApplicationContext 之间进行桥接。Servlet容器允许使用自己的标准注册 Filter 实例,但它不知道Spring定义的Bean。您可以通过标准Servlet容器机制注册 DelegatingFilterProxy ,但将所有工作委托给实现 Filter 的Spring Bean。

下面是 DelegatingFilterProxyFilterChain 中的位置:

DelegatingFilterProxyApplicationContext 查找Bean Filter 0 ,然后调用Bean Filter 0 。下面的清单显示了 DelegatingFilterProxy 的伪代码:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {Filter delegate = getFilterBean(someBeanName);delegate.doFilter(request, response);
}
  1. 延迟获取注册为 Spring Bean 的 Filter。DelegatingFilterProxy 中的delegate 是 Bean Filter 0 的实例。
  2. 将工作委托给 Spring Bean。

DelegatingFilterProxy 的另一个好处是它允许延迟查找 Filter bean实例。这很重要,因为容器需要在启动之前注册 Filter 实例。然而,Spring通常使用 ContextLoaderListener 来加载Spring Bean,直到需要注册 Filter 实例之后才完成。

FilterChainProxy

Spring Security 的 Servlet 支持包含在 FilterChainProxy 中。 FilterChainProxy 是Spring Security提供的一个特殊的 Filter ,它允许通过 SecurityFilterChain 委托给许多 Filter 实例。由于 FilterChainProxy 是一个Bean,它通常被包装在DelegatingFilterProxy中。

下图显示了 FilterChainProxy 的角色。

SecurityFilterChain

SecurityFilterChain 被FilterChainProxy用来确定应该为当前请求调用哪些Spring Security Filter 实例。

下图显示了 SecurityFilterChain 的角色。

SecurityFilterChain 中的安全过滤器通常是 Bean,但它们注册到 FilterChainProxy 而不是DelegatingFilterProxy。 FilterChainProxy 提供了许多直接注册 Servlet 容器或 DelegatingFilterProxy 的优点。

  • 首先,它为所有Spring Security的Servlet支持提供了一个起点。出于这个原因,如果您尝试对 Spring Security 的 Servlet 支持进行故障排除,在 FilterChainProxy 中添加调试点是一个很好的开始。
  • 其次,由于 FilterChainProxy 是 Spring Security 使用的核心,它可以执行不被视为可选的任务。例如,它清除了 SecurityContext 以避免内存泄漏。它还应用 Spring Security 的 HttpFirewall 来保护应用程序免受某些类型的攻击。
  • 此外,它在确定何时应调用 SecurityFilterChain 时提供了更大的灵活性。在 Servlet 容器中, Filter 实例仅根据URL调用。然而, FilterChainProxy 可以通过使用 RequestMatcher 接口来基于 HttpServletRequest 中的任何内容确定调用。

下图显示了 Multiple SecurityFilterChain 实例:

在 Multiple SecurityFilterChain 图中, FilterChainProxy 决定应该使用哪个 SecurityFilterChain 。仅调用第一个匹配的 SecurityFilterChain 。如果请求的URL为 /api/messages/ ,则它首先匹配 /api/**SecurityFilterChain0 模式,因此仅调用 SecurityFilterChain0 ,即使它也匹配 SecurityFilterChainn 。如果请求的URL为 /messages/ ,则它与 /api/**SecurityFilterChain0 模式不匹配,因此 FilterChainProxy 继续尝试每个 SecurityFilterChain 。假设没有其他 SecurityFilterChain 实例匹配,则调用 SecurityFilterChainn

请注意, SecurityFilterChain0 只配置了三个安全性 Filter 实例。但是, SecurityFilterChainn 配置了四个安全 Filter 实例。值得注意的是,每个 SecurityFilterChain 都可以是唯一的,并且可以单独配置。事实上,如果应用程序希望 Spring Security 忽略某些请求,则 SecurityFilterChain 可能没有安全性 Filter 实例。

Security Filters

安全过滤器通过 SecurityFilterChain API 插入 FilterChainProxy。这些过滤器可以用于许多不同的目的,如身份验证、授权、漏洞利用保护等。过滤器以特定的顺序执行,以保证它们在正确的时间被调用,例如,执行身份验证的 Filter 应该在执行授权的 Filter 之前被调用。通常不需要知道 Spring Security 的 Filter 的顺序。然而,有时候知道排序是有益的,如果你想知道它们,你可以查看 org.springframework.security.config.annotation.web.builders.FilterOrderRegistration.java 代码。部分代码如下图:

image-20240124164556175

打印Security Filters

WebSecurityConfig 配置类上修改@EnableWebSecurity注解

@EnableWebSecurity(debug = true)

启动服务可以看到终端中有提示信息输出

image-20240124173520533

前端请求接口,可以看到info信息

image-20240124173653343

将自定义过滤器添加到过滤器链

  1. 实现 Filter 接口

    public class TenantFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;String tenantId = request.getHeader("X-Tenant-Id"); boolean hasAccess = isUserAllowed(tenantId); if (hasAccess) {filterChain.doFilter(request, response); return;}throw new AccessDeniedException("Access denied"); }
    }
    
  2. 将自定义 Filter 添加到 Security Filter Chain 中

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http// ....addFilterBefore(new TenantFilter(), AuthorizationFilter.class);return http.build();
    }
    

    通过在 AuthorizationFilter 之前添加过滤器,我们可以确保在身份验证过滤器之后调用 TenantFilter 。您还可以使用 HttpSecurity#addFilterAfter 将过滤器添加到特定过滤器之后,或使用 HttpSecurity#addFilterAt 将过滤器添加到过滤器链中的特定过滤器位置。

如果您仍然想将 filter 声明为 Spring bean 以利用依赖注入,并避免重复调用,则可以通过声明 FilterRegistrationBean bean并将其 enabled 属性设置为 false 来告诉Spring Boot不要将其注册到容器:

@Bean
public FilterRegistrationBean<TenantFilter> tenantFilterRegistration(TenantFilter filter) {FilterRegistrationBean<TenantFilter> registration = new FilterRegistrationBean<>(filter);registration.setEnabled(false);return registration;
}

Handling Security Exceptions

ExceptionTranslationFilter 允许将 AccessDeniedExceptionAuthenticationException 转换为HTTP响应。

ExceptionTranslationFilter 作为安全过滤器之一插入FilterChainProxy。

下图显示了 ExceptionTranslationFilter 与其他组件的关系:

  1. 首先,ExceptionTranslationFilter调用FilterChain.doFilter(request, response)应用程序的其余部分。
  2. 如果用户未经过身份验证或者是AuthenticationException,则开始身份验证
    • SecurityContextHolder被清除。
    • HttpServletRequest保存后,以便在身份验证成功后可用于重放原始请求。
    • 用于AuthenticationEntryPoint向客户端请求凭据。例如,它可能会重定向到登录页面或发送WWW-Authenticate标头。
  3. 否则,如果它是AccessDeniedException,则Access Denied。调用AccessDeniedHandler来处理拒绝访问。

如果应用程序不抛出 anAccessDeniedException或 an AuthenticationExceptionExceptionTranslationFilter则不执行任何操作。

// 伪代码
try {filterChain.doFilter(request, response); 
} catch (AccessDeniedException | AuthenticationException ex) {if (!authenticated || ex instanceof AuthenticationException) {startAuthentication(); } else {accessDenied(); }
}

Saving Requests Between Authentication

当请求没有身份验证并且是针对需要身份验证的资源时,需要保存已验证资源的请求,以便在身份验证成功后重新请求。在Spring Security中,这是通过使用 RequestCache 实现保存 HttpServletRequest 来完成的。

RequestCache

HttpServletRequest 保存在 RequestCache 中。当用户成功通过身份验证时,使用 RequestCache 来重放原始请求。 RequestCacheAwareFilter 是使用 RequestCache 来保存 HttpServletRequest 的。

默认情况下,使用 HttpSessionRequestCache 。下面的代码演示了如何自定义 RequestCache 实现,如果存在名为 continue 的参数,则该实现用于检查 HttpSession 是否已保存请求。

@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {HttpSessionRequestCache requestCache = new HttpSessionRequestCache();requestCache.setMatchingRequestParameterName("continue");http// ....requestCache((cache) -> cache.requestCache(requestCache));return http.build();
}

Prevent the Request From Being Saved

您可能不希望在会话中存储用户的未经身份验证的请求,原因有很多。您可能希望将该存储卸载到用户的浏览器上或将其存储在数据库中。或者您可能希望关闭此功能,因为您总是希望将用户重定向到主页,而不是他们在登录前试图访问的页面。

要做到这一点,您可以使用 NullRequestCache 实现。

@Bean
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {RequestCache nullRequestCache = new NullRequestCache();http// ....requestCache((cache) -> cache.requestCache(nullRequestCache));return http.build();
}

RequestCacheAwareFilter

RequestCacheAwareFilter 使用 RequestCache 来保存 HttpServletRequest

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

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

相关文章

《游戏-01_3D-开发》之—人物动画控制器

创建变量&#xff0c; 创建线&#xff0c; 连接&#xff0c; 选中线会变为蓝色&#xff0c;新增变量&#xff0c; 设置线&#xff0c; 双击子层进入子层&#xff0c; 创建变量&#xff0c; 双击SkillPanel 拖拽好之后返回上一层&#xff0c; 依次连接&#xff0c; 设置线&#…

[Tomcat] [从安装到关闭] MAC部署方式

安装Tomcat 官网下载&#xff1a;Apache Tomcat - Apache Tomcat 9 Software Downloads 配置Tomcat 1、输入cd空格&#xff0c;打开Tomca目录&#xff0c;把bin文件夹直接拖拉到终端 2、授权bin目录下的所有操作&#xff1a;终端输入[sudo chmod 755 *.sh]&#xff0c;回车 …

【GitHub项目推荐--不错的 Go 学习项目】【转载】

开源实时性能分析平台 Pyroscope 是基于 Go 的开源实时性能分析平台&#xff0c;在源码中添加几行代码 pyroscope 就能帮你找出源代码中的性能问题和瓶颈、CPU 利用率过高的原因&#xff0c;调用树展示帮助你理解程序&#xff0c;支持 Go、Python、Ruby 语言。 Pyroscope 可以…

k8s的图形化工具---rancher

rancher是一个开源的企业级多集群的k8s管理平台。 rancher和k8s的区别&#xff1a;都是为了容器的调度和编排系统。但是rancher不仅可以调度还可以管理整个k8s集群。 rancher自带监控(普罗米修斯) 实验部署 master01 20.0.0.32 node01 20.0.0.34 node02 20.0.0.35 test …

【Java Kubernates】Java调用kubernates提交Yaml到SparkOperator

背景 目前查询框架使用的是trino&#xff0c;但是trino也有其局限性&#xff0c;需要准备一个备用的查询框架。考虑使用spark&#xff0c;spark operator也已经部署到k8s&#xff0c;现在需要定向提交spark sql到k8s的sparkoperator上&#xff0c;使用k8s资源执行sql。 对比 …

linux安装docker--更具官网教程

1.访问https://docs.docker.com/ 2.进入download 3输入cento 或者直接访问地址Install Docker Engine on CentOS | Docker Docs 4一步一步根据官网命令走 2安装 3 4 方式一&#xff1a; service docker start&#xff08;开启&#xff09; service docker status&#xff08…

使用PowerShell命令行,批量修改文件编码

目录 ■前言 ■PowerShell命令 ■效果 ■前言 今天统计修改代码量&#xff0c;使用工具时&#xff0c;发现有些代码无法统计。 原因时UTF-8中有某些特殊字符&#xff0c;工具不能识别。 但是&#xff0c;如果把代码转换为SJIS格式&#xff0c;就能正常统计了。 因此&…

听筒及麦克风电路时序分析

打电话的时候。当没有免提的时候&#xff0c;用的是mic1&#xff0c;麦克风1居然是在J7尾插座子上&#xff0c;所以要把手机的下面贴近嘴巴。mic1的信号给到音频编解码u21&#xff0c;u21通过i2s线给cpu, 然后给基带cpu,然后通过射频发射出去。当要听声音的时候&#xff0c;射频…

【数学建模】插值与拟合

文章目录 插值插值方法用Python解决插值问题 拟合最小二乘拟合数据拟合的Python实现 适用情况 处理由试验、测量得到的大量数据或一些过于复杂而不便于计算的函数表达式时&#xff0c;构造一个简单函数作为要考察数据或复杂函数的近似 定义 给定一组数据&#xff0c;需要确定满…

【软件测试】学习笔记-性能测试场景的分类

性能测试场景的重要程度类似于业务测试的 case&#xff0c;case 是你进行业务测试的指引&#xff0c;case 是否完善也直接决定了测试的覆盖率。同理&#xff0c;场景是传递执行性能测试的步骤和目的&#xff0c;关于这两点是你一定要清楚的。 首先认识下最重要的三个性能场景&…

Java项目:12 Springboot的垃圾回收管理系统

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 1.介绍 垃圾分类查询管理系统&#xff0c;对不懂的垃圾进行查询进行分类并可以预约上门回收垃圾。 让用户自己分类垃圾&#xff0c; 按国家标准自己分类&#x…

解读IP风险画像标签:深度洞察网络安全

在当今数字化的世界中&#xff0c;网络安全成为企业和个人关注的焦点。IP风险画像标签作为网络安全的利器&#xff0c;扮演着深度洞察网络风险的角色。本文将深入解读IP风险画像标签&#xff0c;揭示其在网络安全领域的重要性和功能。 1. IP风险画像标签是什么&#xff1f; I…

Jmeter-解析返回参数-解析并操作json

工作中经常会遇到JSON字符串&#xff0c;接口的入参和返回参数也多数是JSON格式&#xff0c;自动化项目中常需要写脚本处理返回结果&#xff0c;本文总结java或jmeter的beanshell脚本中对于json的常用操作 json字符串的格式 简单的JSON字符串&#xff1a;{“key”:“value”,“…

【服务器数据恢复】EqualLogic存储磁盘坏道导致存储不可用的数据恢复案例

服务器数据恢复环境&故障&#xff1a; 某公司IT部门一台某品牌EqualLogic PS6100系列存储在运行过程中突然崩溃。 服务器管理员对故障服务器存储进行初步检查&#xff0c;经过检测发现导致该服务器存储无法正常工作的原因是该存储中raid5磁盘阵列内有2块硬盘出现故障离线&a…

数字图像处理(实践篇)二十七 Python-OpenCV 滑动条的使用

目录 1 涉及的函数 2 实践 1 涉及的函数 ⒈ setWindowProperty()用于设置GUI应用程序的属性 cv2.setWindowProperty(windowsName, prop_id, prop_value) 参数: ①

UI 自动化测试框架:PO 模式+数据驱动

1. PO 设计模式简介 什么是 PO 模式&#xff1f; PO&#xff08;PageObject&#xff09;设计模式将某个页面的所有元素对象定位和对元素对象的操作封装成一个 Page 类&#xff0c;并以页面为单位来写测试用例&#xff0c;实现页面对象和测试用例的分离。 PO 模式的设计思想与…

Nodejs--Linux环境安装及配置

一、下载安装包 &#xff08;1&#xff09;通过命令uname -a 查看Linux系统版本。 &#xff08;2&#xff09;打开官网下载地址&#xff1a; https://www.nodejs.com.cn/ 选择对应的版本下载安装包。 &#xff08;3&#xff09;将下载好的安装包传到Linux对应目录进行解压。…

想要透明拼接屏展现更加效果,视频源是技术活,尤其作为直播背景

随着科技的飞速发展&#xff0c;视频制作和显示技术也在不断进步。透明拼接屏视频作为一种新型的视频形式&#xff0c;在许多场合都得到了广泛的应用。尼伽小编将深入探讨透明拼接屏视频的制作过程、要求、清晰度&#xff0c;以及目前常作为直播背景的优势。 一、透明拼接屏视频…

力扣hot100 两两交换链表中的节点 双指针

Problem: 24. 两两交换链表中的节点 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1) Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { …

国民技术N32G430C8开发笔记二-UART驱动开发

参考demo E:\tfs\data\smartsafe\N32G430\Nations.N32G430_Library.1.0.0\projects\n32g430_EVAL\examples\USART\Interrupt开发uart1和uart3驱动。Uart1用于通信&#xff0c;uart3用于调试。 参考用户手册5.2.5复用功能。Uart1_tx引脚使用PA9&#xff0c;重映射使用AF5&#x…