深入浅出Spring Security
一、Spring Security基本组件
Spring Security的设计理念是提供一种可插拔的、高度可定制的安全服务。其核心功能依赖于以下几个关键组件:
-
Authentication (认证):
- 概念: 确认用户身份的过程,即验证“你是谁”。
- 核心类:
Authentication
接口,代表当前的认证信息,包含用户名、密码、权限等。UsernamePasswordAuthenticationToken
是最常见的实现。 - 相关组件:
AuthenticationManager
: 认证管理器接口,负责验证Authentication
对象。其常用实现是ProviderManager
。AuthenticationProvider
: 认证提供者接口,ProviderManager
内部维护一个AuthenticationProvider
列表,每个提供者负责一种特定的认证方式(如用户名密码认证、OAuth认证等)。DaoAuthenticationProvider
是最常用的实现,它从用户详情服务获取用户信息进行验证。
-
Authorization (授权):
- 概念: 确定认证后的用户是否有权限执行特定操作的过程,即验证“你能做什么”。
- 核心类:
AccessDecisionManager
接口,负责做出授权决策。AbstractAccessDecisionManager
是常用实现。 - 相关组件:
GrantedAuthority
: 授权接口,代表用户被授予的权限(如ROLE_USER
,ROLE_ADMIN
)。SecurityMetadataSource
: 安全元数据源,定义了哪些URL或方法需要哪些权限。FilterSecurityInterceptor
/MethodSecurityInterceptor
: 安全拦截器,负责在请求到达控制器或方法执行前,根据SecurityMetadataSource
和用户的GrantedAuthority
进行权限校验。
-
Web Security Filters (过滤器链):
- Spring Security的核心工作是通过一系列过滤器在
FilterChain
中执行。最核心的是FilterChainProxy
,它内部维护了一个过滤器链(FilterChain
列表)。 - 关键过滤器:
ChannelProcessingFilter
: 强制协议(如HTTPS)。ConcurrentSessionFilter
: 处理并发会话控制。SecurityContextPersistenceFilter
: 在请求开始时加载SecurityContext
,结束时保存。UsernamePasswordAuthenticationFilter
/DefaultLoginPageGeneratingFilter
: 处理基于表单的认证。BasicAuthenticationFilter
: 处理HTTP Basic认证。RequestCacheAwareFilter
: 处理请求缓存。SecurityContextHolderFilter
(旧版概念,新版本整合): 确保安全上下文可用。FilterSecurityInterceptor
: 执行基于URL的访问控制。ExceptionTranslationFilter
: 捕获安全异常并转换为合适的响应(如跳转到登录页、返回403)。
- Spring Security的核心工作是通过一系列过滤器在
-
UserDetailsService:
- 定义了一个从数据源(如数据库、内存)加载用户详细信息的方法
loadUserByUsername(String username)
。返回UserDetails
对象,包含用户名、密码、权限等信息。开发者需要实现这个接口来提供自己的用户数据加载逻辑。
- 定义了一个从数据源(如数据库、内存)加载用户详细信息的方法
-
Security Context:
SecurityContextHolder
类持有当前线程的SecurityContext
,SecurityContext
中包含当前的Authentication
对象。通过它,应用中的任何代码都可以获取当前认证用户的信息。
二、Spring Security应用场景
Spring Security的应用场景非常广泛,几乎涵盖了Web应用安全的所有方面:
- 用户认证: 支持多种认证方式,如用户名/密码表单登录、HTTP Basic/Digest认证、OAuth2、JWT、SAML、CAS等第三方认证、Remember-Me功能等。
- 授权控制:
- 基于URL的访问控制: 配置哪些URL路径需要登录,以及登录后需要哪些角色/权限才能访问。
- 方法级安全: 使用注解(如
@PreAuthorize
,@Secured
)控制对Spring管理的Bean方法的访问。 - 域对象安全: 对特定对象(如订单、用户信息)的CRUD操作进行权限控制。
- 会话管理: 并发会话控制(如同一用户只能有一个登录会话)、会话固定保护、会话超时处理。
- CSRF防护: 默认启用CSRF(跨站请求伪造)防护,保护应用免受此类攻击。
- 安全头部: 自动添加安全相关的HTTP头部,如
X-Content-Type-Options
,X-Frame-Options
等,增强应用安全性。 - 密码编码: 提供强大的密码编码器(如BCryptPasswordEncoder),安全地存储用户密码。
三、Spring Security执行流程(以基于表单的认证为例)
当用户访问一个需要认证的页面时,Spring Security的执行流程大致如下:
- 请求到达: 用户浏览器发送请求到服务器。
- 过滤器链处理: 请求首先经过
FilterChainProxy
,然后进入其内部的过滤器链。 - 安全上下文检查:
SecurityContextPersistenceFilter
检查当前线程是否有SecurityContext
(即用户是否已认证)。如果没有,则创建一个空的。 - 路径匹配与拦截:
FilterSecurityInterceptor
根据配置的安全规则(如antMatchers("/admin/**").hasRole("ADMIN")
),判断当前请求路径是否需要认证以及需要哪些权限。 - 认证检查: 如果用户未认证(
SecurityContext
中没有有效的Authentication
),ExceptionTranslationFilter
会捕获这个情况,并决定如何处理:- 如果是登录请求(如
/login
),则允许请求继续。 - 如果不是登录请求,则根据配置(通常是
formLogin()
配置)将用户重定向到登录页面(由DefaultLoginPageGeneratingFilter
或自定义的登录页处理)。
- 如果是登录请求(如
- 登录处理: 用户填写表单并提交登录请求。
- 认证过滤器处理:
UsernamePasswordAuthenticationFilter
拦截到登录请求,从请求中提取用户名和密码。 - 认证提供者验证:
Filter
将用户名和密码封装成Authentication
对象(通常是UsernamePasswordAuthenticationToken
的不完整形式,只有用户名),然后提交给AuthenticationManager
(通常是ProviderManager
)。 - 用户详情加载:
ProviderManager
会委托给内部的AuthenticationProvider
(如DaoAuthenticationProvider
),该提供者会调用UserDetailsService
的loadUserByUsername
方法,从数据库等地方加载完整的用户信息(包括密码和权限)。 - 密码匹配:
AuthenticationProvider
使用配置的PasswordEncoder
比较用户提交的密码和从UserDetailsService
加载的密码是否一致。 - 认证结果:
- 成功: 如果密码匹配成功,
AuthenticationProvider
会创建一个完整的、已认证的Authentication
对象(包含用户名、密码、权限等),并标记为已认证(setAuthenticated(true)
)。这个对象被传递回AuthenticationManager
,然后存储到SecurityContext
中。SecurityContextPersistenceFilter
在请求结束时将其保存(通常是放入Session)。 - 失败: 如果密码不匹配或其他原因导致认证失败,会抛出
AuthenticationException
。ExceptionTranslationFilter
会捕获该异常,通常返回一个错误信息给用户(如登录页显示“用户名或密码错误”)。
- 成功: 如果密码匹配成功,
- 后续请求: 用户再次访问受保护的资源时,
SecurityContextPersistenceFilter
会从Session中恢复SecurityContext
,后续的FilterSecurityInterceptor
就能根据其中已认证的Authentication
对象进行授权判断。
四、常见业务问题案例
在使用Spring Security的过程中,开发者可能会遇到一些常见的问题:
-
问题: 登录成功后,访问受保护资源仍然被重定向到登录页。
- 可能原因:
- 密码编码器配置错误:
UserDetailsService
返回的UserDetails
中的密码没有使用与登录时相同的PasswordEncoder
进行编码。 SecurityContext
没有正确保存或恢复:检查SecurityContextPersistenceFilter
的配置。- 会话问题:浏览器禁用了Cookie或Session失效。
- 权限配置错误:虽然登录成功,但用户没有访问目标URL所需的权限。
- 密码编码器配置错误:
- 排查思路: 检查密码编码器配置一致性,检查安全过滤器链配置,查看控制台日志,检查浏览器开发者工具的网络请求和Cookie。
- 可能原因:
-
问题: 使用
@PreAuthorize
注解进行方法级权限控制时,注解不生效。- 可能原因:
- 忘记启用方法级安全:在配置类上缺少
@EnableGlobalMethodSecurity(prePostEnabled = true)
或@EnableMethodSecurity(prePostEnabled = true)
(Spring Security 5+)。 MethodSecurityInterceptor
没有正确配置或加入过滤器链。- 表达式语法错误:检查
@PreAuthorize
中的SpEL表达式是否正确,特别是角色前缀(如hasRole('ADMIN')
默认会自动添加ROLE_
前缀,如果数据库存储的是ADMIN
而非ROLE_ADMIN
,需要调整)。
- 忘记启用方法级安全:在配置类上缺少
- 排查思路: 检查配置类上的注解,确认
MethodSecurityInterceptor
的Bean定义,仔细核对SpEL表达式和角色名称。
- 可能原因:
-
问题: 并发会话控制不生效,同一用户可以在多个浏览器/标签页同时登录。
- 可能原因:
- 没有启用或正确配置并发会话控制:检查
sessionManagement().maximumSessions()
配置。 - Session ID生成或管理有问题。
- 前端可能存在多个Session ID被同时使用的情况。
- 没有启用或正确配置并发会话控制:检查
- 排查思路: 检查
sessionManagement()
配置,查看日志中关于会话创建和失效的信息,确认是否按照预期阻止了新的会话。
- 可能原因:
-
问题: CSRF防护导致POST请求失败,返回403。
- 可能原因:
- 前端没有正确包含CSRF Token:对于非简单请求(如POST、PUT、DELETE等),需要在请求头或请求体中携带CSRF Token。
- 前端获取的Token与后端验证的Token不匹配:可能是Token过期或获取方式错误。
- 排查思路: 检查前端代码是否从
X-CSRF-TOKEN
响应头或_csrf
隐藏字段获取Token,并正确地在请求中发送。使用浏览器开发者工具检查请求头。
- 可能原因:
-
问题: 自定义登录页无法正常跳转或表单提交后无响应。
- 可能原因:
- 自定义登录页URL配置错误:
formLogin().loginPage("/myLogin")
中的路径是否正确。 - 登录处理URL配置错误:默认是
/login
,如果修改了(如loginProcessingUrl("/doLogin")
),前端表单的action
属性必须与之匹配。 - CSRF Token问题:自定义登录页也需要处理CSRF Token。
- 前端路由或框架(如React, Vue)与Spring Security的交互问题。
- 自定义登录页URL配置错误:
- 排查思路: 仔细核对自定义登录页的配置,检查前端表单的
action
和CSRF处理,确保URL匹配。对于前端框架,可能需要特殊处理路由跳转和表单提交。
- 可能原因:
五、总结
Spring Security是一个功能强大且复杂的框架,但它极大地简化了Web应用安全性的实现。理解其核心组件、熟悉常见应用场景、掌握基本执行流程,并学会排查常见问题,是熟练使用它的关键。虽然配置起来可能有些繁琐,但其带来的安全性和可维护性是值得投入时间和精力去学习的。希望这篇博客能帮助你更好地理解和应用Spring Security,为你的应用构建坚固的安全防线。
相关文章:
深入浅出Spring Security
一、Spring Security基本组件 Spring Security的设计理念是提供一种可插拔的、高度可定制的安全服务。其核心功能依赖于以下几个关键组件: Authentication (认证): 概念: 确认用户身份的过程,即验证“你是谁”。核心类: Authentication 接口,…...

基于51单片机的红外防盗及万年历仿真
目录 具体实现功能 设计介绍 资料内容 全部内容 资料获取 具体实现功能 具体功能: (1)实时显示年、月、日、时、分、秒、星期信息; (2)红外传感器(仿真中用按键模拟)检测是否有…...
Doris 数据库深度解析:架构、原理与实战应用
一、Doris 的架构与原理 1. 架构组成 Doris 是一个分布式 MPP(大规模并行处理)数据库,它的架构主要由以下几部分组成: FE(Frontend):负责管理元数据、解析 SQL 查询、优化查询计划࿰…...

【飞腾AI加固服务器】全国产化飞腾+昇腾310+PCIe Switch的AI大模型服务器解决方案
以下是全国产化飞腾AI加固服务器采用飞腾昇腾PCIe Switch解决方案: 🖥️ 一、硬件架构亮点 国产算力双擎 飞腾处理器:搭载飞腾FT2000/64核服务器级CPU(主频1.8-2.2GHz),支持高并发任务与复杂计算&a…...
【术语扫盲】评估指标Precision、Recall、F1-score、Support是什么含义?
一、背景 Precision、Recall、F1-score、Support 是分类问题中最常用的评估指标,它们是机器学习、深度学习、数据挖掘中非常基础也非常重要的术语。 二、 详细解释 指标含义公式Precision(精准率)预测为某类的样本中,有多少是真…...

应用层协议:HTTPS
目录 HTTPS:超文本传输安全协议 1、概念 2、通信过程及关键技术 2.1 通信过程 1> TLS握手协商(建立安全通道) 2> 加密数据传输 2.2 关键技术 1> 对称加密算法 2> 非对称加密 3> 对称加密和非对称加密组合 4> 数…...

【ArcGIS技巧】—村庄规划规划用地规划状态字段生成工具
"国土空间规划后续也是走向数据治理,数据建库已经是涉及到城市规划、建筑、市政、农业、地理信息、测绘等等方方面面。不得不说以后数据库建设跟维护,是很多专业的必修课。小编就湖南省的村庄规划建库过程中规划用地用海中规划状态字段写了个小工具…...
React从基础入门到高级实战:React 实战项目 - 项目三:实时聊天应用
React 实战项目:实时聊天应用 欢迎来到本 React 开发教程专栏 的第 28 篇!在前 27 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和架构模式等核心知识。这一次,…...
Go语言中的if else控制语句
if else是Go语言中最基础也最常用的条件控制语句,用于根据条件执行不同的代码块。下面我将详细介绍Go语言中if else的各种用法和特性。 1. 基本语法 1.1. 最简单的if语句 if 条件表达式 {// 条件为true时执行的代码 } 示例: if x > 10 {fmt.Prin…...

【PCIe总线】-- inbound、outbound配置
PCI、PCIe相关知识整理汇总 【PCIe总线】 -- PCI、PCIe相关实现 由之前的PCIe基础知识可知,pcie的组成有:RC(根节点)、siwtch(pcie桥)、EP(设备)。 RC和EP,以及EP和EP能…...

分布式锁实战:Redisson vs. Redis 原生指令的性能对比
分布式锁实战:Redisson vs. Redis 原生指令的性能对比 引言 在DIY主题模板系统中,用户可自定义聊天室的背景、图标、动画等元素。当多个运营人员或用户同时修改同一模板时,若没有锁机制,可能出现“甲修改了背景色,乙…...
MyBatis中foreach集合用法详解
在 MyBatis 中,<foreach> 标签用于遍历集合(Collection、List、Array、Map),常用于构建动态 SQL 语句(如 IN 查询、批量插入等)。以下是详细用法和示例: 核心属性 属性描述collection必填…...

react+taro 开发第五个小程序,解决拼音的学习
1.找一个文件夹 cmd 2.taro init 3.vscode 找开该文件夹cd help-letters 如:我的是(base) PS D:\react\help-letters> pnpm install 4.先编译一下吧。看下开发者工具什么反应。 pnpm dev:weapp 5.开始规则。我用cursor就是不成功。是不是要在这边差不多了&…...
高防IP可以防护什么攻击类型?企业网络安全的第一道防线
“高防IP”成为企业构建网络安全防护体系的重要一环。尤其是对于金融、电商、游戏、政务等业务高度依赖网络稳定性的行业而言,确保系统724小时正常运行已经成为基本要求。高防IP到底可以防护哪些攻击类型?它又是如何帮助企业抵御风险、保障服务稳定运行的…...
Wireshark使用教程(含安装包和安装教程)
Wireshark使用入门教程 0.资源下载以及软件安装1.Wireshark中无法显示网卡列表2.Wireshark抓取H264过程 0.资源下载以及软件安装 参考blog: 抓包神器wireshark安装保姆级教程 压缩包下载:Wireshark安装包 1.Wireshark中无法显示网卡列表 Wireshark中无法显示网…...
Asp.Net Core基于StackExchange Redis 缓存
NuGet安装 StackExchange.Redis Microsoft.Extensions.Options 0. appsettings.json初始化配置 {"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHos…...
【Linux】SSH:免密登录
配置 SSH 的免密登录(基于公钥认证)可实现无需输入密码即可登录远程主机,常用于自动化脚本、服务器集群、DevOps 等场景。 生成本地 SSH 密钥对(若尚未存在) 在本地客户端执行: ssh-keygen -t rsa -b 409…...

kafka(windows)
目录 介绍 下载 配置 测试 介绍 Kafka是一个分布式流媒体平台,类似于消息队列或企业信息传递系统。 下载 Kafka对于Zookeeper是强依赖,所以安装Kafka之前必须先安装zookeeper 官网:Apache Kafka 下载此安装包并解压 配置 新建log…...
深度学习习题3
1.训练神经网络过程中,损失函数在一些时期(Epoch)不再减小, 原因可能是: 1.学习率太低 2.正则参数太大 3.卡在了局部最小值 A1 and 2 B. 2 and 3 C. 1 and 3 D. 都是 2.对于分类任务,我们不是将神经网络中的随机权重…...
勒让德多项式
勒让德多项式 (Legendre) 当区间为 [ − 1 , 1 ] [-1,1] [−1,1],权函数 ρ ( x ) 1 ρ(x)1 ρ(x)1时,由 1 , x , . . . , x n , . . . {1,x,...,x^n,...} 1,x,...,xn,...正交化得到的多项式称为勒让德多项式,并用 P 0 ( x ) , P 1 ( x ) ,…...
atc abc409E
原题链接:E - Pair Annihilation 题目背景: n 个点 n - 1 条边的有权无向图,每个点都有一个值,两个连通的点的值可以互相抵消,既将u 的 -1 传给 v 时可以抵消掉 v 的 1 并花费边权值;求最小花费。 考察算…...
Mysql批处理写入数据库
在学习mybatisPlus时,看到一个原本没用过的参数: rewriteBatchedStatementstrue 将上述代码装入jdbc的url中即可使数据库启用批处理写入。 需要注意的是,这个参数仅适用于MySQL JDBC 驱动的私有扩展参数。 作用原理是: 原本的…...

基于安卓的文件管理器程序开发研究源码数据库文档
摘 要 伴随着现代科技的发展潮流,移动互联网技术快速发展,各种基于通信技术的移动终端设备做的也越来越好了,现代智能手机大量的进入到了我们的生活中。电子产品的各种软硬技术技术的发展,操作系统的不断更新换代,谷歌…...

EMC VNXe 存储系统日志收集方法
写在前面 有朋友找来看看VNXe的故障,这种问题总是要收集日志,顺便这里也分享给大家。 注意,VNXe和VNX 属于完全不同的产品,不要看名字很类似,操作系统已经完全重构了,如果说是否有联系,大概就…...
嵌入式链表操作原理详解
嵌入式链表操作原理详解 链表是嵌入式软件开发中最基础的数据结构之一,其设计采用嵌入式链表节点的思想,实现了高度通用的链表管理机制。以下是核心原理和操作的全面解析: 一、基础数据结构 struct list_head {struct list_head *next, *pr…...

从“人找政策”到“政策找人”:智能退税ERP数字化重构外贸生态
离境退税新政核心内容与外贸企业影响 (一)政策核心变化解析 退税商店网络扩容 新政明确鼓励在大型商圈、旅游景区、交通枢纽等境外旅客聚集地增设退税商店,并放宽备案条件至纳税信用M级企业。以上海为例,静安区计划新增1000家退…...
一.设计模式的基本概念
一.核心概念 对软件设计中重复出现问题的成熟解决方案,提供代码可重用性、可维护性和扩展性保障。核心原则包括: 1.1. 单一职责原则 定义:一个类只承担一个职责,避免因职责过多导致的代码耦合。 1.2. 开闭原则 定义…...

以人类演示视频为提示,学习可泛化的机器人策略
25年5月来自清华大学、上海姚期智研究院和星动纪元(RoboEra)公司的论文“Learning Generalizable Robot Policy with Human Demonstration Video as a Prompt”。 最近的机器人学习方法通常依赖于从通过遥操作收集的大量机器人数据集中进行模仿学习…...
split方法
在编程中,split 方法通常用于将字符串按照指定的分隔符拆分成多个部分,并返回一个包含拆分结果的列表(或数组)。不同编程语言中的 split 方法语法略有不同,但核心功能相似。以下是常见语言中的用法: 1. P…...

SOC-ESP32S3部分:36-适配自己的板卡
飞书文档https://x509p6c8to.feishu.cn/wiki/RP4UwPrsKi4xuQkKLAAcKxD3n1b 如果你自己画了PCB板,需要把自己绘制的板卡配置小智AI工程,可以参考此文档。 下载源码 克隆或下载源码到本地,这里以1.5.5为例,大家可以自行修改其它版…...