Spring Security架构

news2024/12/28 17:44:29

文章目录

  • 过滤器回顾
  • 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 application
    chain.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 {
    
        @Override
        public 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.coloradmin.cn/o/1408819.html

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

相关文章

1.24号c++

C绪论 c是c语言的扩充&#xff0c;C包含了C的所有属性&#xff0c;换一句话说&#xff0c;C语言在C中都合法。 C语言编程思想&#xff1a;面向过程 c编程思想&#xff1a;面向对象 可以说在C中一切皆对象。 c的三大属性&#xff1a;封装&#xff0c;继承&#xff0c;多态。…

gin介绍及helloworld

1. 介绍 Gin是一个golang的微框架&#xff0c;封装比较优雅&#xff0c;API友好&#xff0c;源码注释比较明确&#xff0c;具有快速灵活&#xff0c;容错方便等特点 对于golang而言&#xff0c;web框架的依赖要远比Python&#xff0c;Java之类的要小。自身的net/http足够简单&…

DeadLinkHunter工具

一、背景 二月底的时候&#xff0c;提到一个文档中心的链接有效性问题&#xff0c;文档中心的某个超链接跳转后&#xff0c;页面内容是空的或者提示页面内容不存在。 分析一下可知&#xff0c;其实文档中心的每个页面都有很多不定位置、不定数量的超链接&#xff0c;每个超链…

JS进阶-解构赋值(一)

扩展&#xff1a;解构赋值时Js特有的一种处理数据的方式&#xff0c;在Java中没有处理数据的方式 知识引入&#xff1a; 思考&#xff1a;在js中&#xff0c;在没有学习解构赋值之前&#xff0c;我们是如何获取数组的内容的&#xff1f; 以上要么不好记忆&#xff0c;要么书写麻…

css实现右边边框分割线 渐变色,边框四角样式

分割线 代码 .data-item:first-of-type {border-right: 2px solid;border-image: linear-gradient(to top,rgba(0, 0, 0, 0.1) 0%,rgba(81, 110, 197, 0.76) 50%,rgba(0, 0, 0, 0.1) 100%)1;padding: 15px 0;}四角边框样式 代码 .chart-box {cursor: pointer;background: line…

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)

目录 前言 实战开发&#xff1a; 一、Spring Security整合到SSM项目 1. pom文件引入包 2. web.xml 配置 3. 添加 spring-security.xml 文件 二、Spring Security实战应用 1. 项目结构 2. pom文件引入 3. web.xml 配置 4. Spring 配置 applicationContext.xml 5. sp…

PCB【过孔】

1、钻孔的费用通常占PCB制板费用的30%到40%&#xff0c;过孔钻孔&#xff08;drill hole&#xff09; 钻孔周围的焊盘区&#xff0c;这两部分的尺寸大小决定了过孔的大小。过孔越小&#xff0c;其自身的寄生电容也越小。在高速电路中希望越小越好。孔内径原则上要求0.2mm&#…

C4.5决策树的基本建模流程

C4.5决策树的基本建模流程 作为ID3算法的升级版&#xff0c;C4.5在三个方面对ID3进行了优化&#xff1a; &#xff08;1&#xff09;它引入了信息值&#xff08;information value&#xff09;的概念来修正信息熵的计算结果&#xff0c;以抑制ID3更偏向于选择具有更多分类水平…

内网穿透、远程桌面、VPN的理解

最近在研究内网穿透的相关技术&#xff0c;然后回想起一些相关的技术&#xff0c;比如说要远程桌面公司的电脑&#xff0c;VPN连入内网等。然后想着在此处记录一下&#xff0c;各个的区别&#xff0c;这个纯粹是从技术层面的理解&#xff0c;此处不详细解释怎么去实现或者用什么…

深度学习中RGB影像图的直方图均衡化python代码and对图片中指定部分做基于掩模的特定区域直方图均衡化

深度学习很重要的预处理步骤 就是需要对做直方图均衡化 其中主要分成灰度图以及RGB图的直方图均衡化 这俩的方法和代码不同 想要去看具体原理的朋友可以查看下面这篇博客的内容 写的很详细颜色直方图均衡化(https://www.cnblogs.com/wancy/p/17668345.html) 我们这个场景中会用…

C/C++ - 编程语法特性

目录 标准控制台框架 输入输出对象 命名空间 标准控制台框架 头文件 ​#include <iostream>​​ 告诉编译器我们要使用iostream库尖括号中的名字指定了某个头文件(header) 入口函数 ​int main(void)​​ 返回 ​return 0;​​ 输出语句 ​std::cout << "H…

生产力工具|卸载并重装Anaconda3

一、Anaconda3卸载 &#xff08;一&#xff09;官方方案一&#xff08;Uninstall-Anaconda3-不能删除配置文件&#xff09; 官方推荐的方案是两种&#xff0c;一种是直接在Anaconda的安装路径下&#xff0c;双击&#xff1a; &#xff08;可以在搜索栏或者使用everything里面搜…

一站式VR全景婚礼的优势表现在哪里?

你是否想过&#xff0c;婚礼也可以用一种全新的方式呈现&#xff0c;VR全景婚礼让每位用户沉浸式体验婚礼现场感。现在很多年轻人&#xff0c;都想让自己的婚礼与众不同&#xff0c;而VR全景婚礼也是未来发展的方向之一。 很多婚庆公司开通了VR婚礼这一服务&#xff0c;就是通过…

BACnet转MQTT网关BA113

随着通讯技术和控制技术的发展&#xff0c;为了实现楼宇的高效、智能化管理&#xff0c;集中监控管理已成为楼宇智能管理发展的必然趋势。在此背景下&#xff0c;高性能的楼宇暖通数据传输解决方案——协议转换网关应运而生&#xff0c;广泛应用于楼宇自控和暖通空调系统应用中…

如何利用streamlit 將 gemini pro vision 進行圖片內容介紹

如何利用streamlit 將 gemini pro vision 進行圖片內容介紹 1.安裝pip install google-generativeai 2.至 gemini pro 取 api key 3.撰寫如下文章:(方法一) import json import requests import base64 import streamlit as st 讀取圖片檔案&#xff0c;並轉換成 Base64 編…

76.Go分布式ID总览

文章目录 简介一&#xff1a;UUID二、雪花算法三&#xff1a;Leaf-snowflake四&#xff1a;数据库自增ID五&#xff1a;使用Redis实现分布式ID生成六&#xff1a;使用数据库分段&#xff08;Leaf-segment&#xff09;七 &#xff1a;增强版Leaf-segment八&#xff1a;Tinyid九&…

浅学JAVAFX布局

JAVAFX FlowPane布局 Flowpane是一个容器。它在一行上排列连续的子组件&#xff0c;并且如果当前行填充满了以后&#xff0c;则自动将子组件向下推到一行 public class FlowPanedemo extends Application {Overridepublic void start(Stage stage) throws Exception {stage.s…

C++入门篇章1(C++是如何解决C语言不能解决的问题的)

目录 1.C关键字(以C98为例)2.命名空间2.1 命名空间定义2.2命名空间使用 3.C输入&输出4.缺省参数4.1缺省参数概念4.2 缺省参数分类 5. 函数重载5.1函数重载概念5.2 C支持函数重载的原理--名字修饰(name Mangling) 1.C关键字(以C98为例) C总计63个关键字&#xff0c;C语言32…

go api(get post传参,数据库,redis) 测试

介绍&#xff1a;分别测试get请求&#xff0c;post请求&#xff0c;请求链接数据库&#xff0c;以及redis操作。 1.api代码 package mainimport (_ "database/sql""encoding/json""github.com/gin-gonic/gin""go-test/com.zs/database&quo…

【RT-DETR有效改进】交叉形窗口网络 | CSWinTransformer(附代码 + 修改教程)

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持Re…