SpringBoot3整合SpringSecurity6(二)SpringSecurity默默的干了些啥
写在前面
第一节中,我们基本上就引入SpringSecurity依赖,其他什么都没做就完成了认证功能。
之所以我们不用做什么,是因为SpringSecurity默认实现了很多功能。
当然了,这里默认实现都是基于内存的用户认证,即用户都是创建在内存当中的,实际应用都是基于数据库的。
小伙伴们不用着急,只要我们理解了基于内存的用户认证,那基于数据库也是一样的原理,不同的只是一个从内存中获取用户信息,一个从数据库中获取用户信息而已。
接下来,我们来简单看看其基本原理。
一、官方文档
官方文档对SpringSecurity 实现原理其实写的挺详细了。感兴趣的小伙伴可以点下面链接查看
https://docs.spring.io/spring-security/reference/servlet/architecture.html

但对于不少初学者,看官方文档可能会比较吃力。
所以晓凡将其简化,请接着往下看.
二、原理初探
我们以上一篇文章中案例,来看一下SpringSecurity流程。
SpringSecurity的原理其实就是一个过滤器链,如下图所示,每个过滤器各司其职。

上图中,并没有将所有过滤器都例举出来,刚开始,也没必要了解所有过滤器。
下面,我们来看看这几个主要过滤器
① UsernamePasswordAuthenticationFilter
这个过滤器处理用户登录的请求。
就像是保安检查你的门禁卡和密码,确认你是不是小区的合法居民。
② ExceptionTranslationFilter
这个过滤器捕获安全相关的异常,并将其转换为HTTP响应。
就像是保安发现了问题,他会采取相应的措施,比如不让你进入或者给你一个警告信息。
③ FilterSecurityInterceptor
这个过滤器是授权的核心,它决定用户是否有权限执行特定的请求。
就像是保安检查你有没有权限去某个特定的区域。
三、 DefaultSecurityFilterChain类
为啥SpringSecurity默认帮我们实现那么多,其实主要是DefaultSecurityFilterChain的功劳,它加载了默认的15个Filter。
① 我们在源码中找到DefaultSecurityFilterChain 类,并如下图所示加上断点看一下

② 程序启动后,默认加载15个过滤器

四、各个过滤器作用
这里将例举出15个过滤器的作用,小伙伴们简单了解即可,切忌死记硬背,用得多了自然就记住了。
| 过滤器 | 作用 |
|---|---|
DisableEncodeUrlFilter |
用来禁用URL编码。有时候,为了防止CSRF攻击,Spring Security会对重定向的URL进行编码。但如果你确定你的应用环境是安全的,可以用这个过滤器来禁用这个功能。 |
WebAsyncManagerIntegrationFilter |
确保异步请求也能正确处理安全上下文。就像是小区保安需要确保即使是快递或者外卖这样的非正常访问,也能被正确地记录和管理。 |
SecurityContextHolderFilter |
确保每个请求都能正确地获取到安全上下文,也就是知道当前是谁在访问。就像是小区保安需要知道是谁在小区里。 |
HeaderWriterFilter |
会在HTTP响应中添加一些安全相关的头部,比如防止XSS攻击的头部。就像是小区保安会在小区的围墙上安装一些安全设备。 |
CsrfFilter |
防止跨站请求伪造攻击,确保用户的操作是他们自己发起的。就像是小区保安会检查每个人的出入证,确保他们不是被坏人操控。 |
LogoutFilter |
处理用户注销的请求,清除用户的身份信息。就像是小区保安在居民离开时,会注销他们的临时通行证。 |
UsernamePasswordAuthenticationFilter |
处理基于用户名和密码的登录请求。就像是小区保安检查居民的门禁卡和密码。 |
DefaultLoginPageGeneratingFilter |
在需要时生成默认的登录页面。就像是小区保安会给没有门禁卡的访客一个标准的表格来填写信息。 |
DefaultLogoutPageGeneratingFilter |
在需要时生成默认的注销页面。就像是小区保安会给需要离开的居民一个标准的流程来完成注销。 |
BasicAuthenticationFilter |
处理基本的身份验证,也就是基于用户名和密码的认证,但不加密。就像是小区保安检查居民的未加密的门禁卡和密码。 |
RequestCacheAwareFilter |
记住用户最初的请求,如果因为认证被重定向,认证成功后可以回到最初的页面。就像是小区保安记得你最初想去的地方,即使你需要去验证身份,回来后他还能指引你去那里。 |
SecurityContextHolderAwareRequestFilter |
确保每个请求都能正确地访问到安全上下文。就像是小区保安确保每个访客都能被正确地记录和管理。 |
AnonymousAuthenticationFilter |
为匿名用户创建一个认证 token。就像是小区保安会给没有门禁卡的访客一个临时的通行证。 |
ExceptionTranslationFilter |
捕获安全相关的异常,并将其转换为HTTP响应,比如401未授权或403禁止访问。就像是小区保安在发现问题时,会采取相应的措施,比如不让进入或者给出一个错误信息。 |
AuthorizationFilter |
负责检查用户是否有权限执行特定的请求。就像是小区保安会检查你有没有权限去某个特定的区域。 |
五、基于内存的用户认证
在上面流程图中,我们提到了UsernamePasswordAuthenticationFilter 这个过滤器。用户认证就是在这个过滤器中完成的。
这个过滤器的职责就是:将内存中的用户信息获取出来,再和我们界面上输入的用户名和密码进行比较。
如果比较成功,认证成功,允许用户访问资源;如果比较失败,用户认证失败,拒绝访问。
5.1 认证流程

- 用户提交登录请求:用户在登录页面输入用户名和密码,然后提交给服务器。
- UsernamePasswordAuthenticationFilter拦截用户请求:这个过滤器会拦截登录请求,从请求中提取用户名和密码,创建一个
UsernamePasswordAuthenticationToken对象。 - AuthenticationManager处理认证:
UsernamePasswordAuthenticationFilter将UsernamePasswordAuthenticationToken传递给AuthenticationManager进行认证。 - ProviderManager遍历AuthenticationProvider:
AuthenticationManager的默认实现ProviderManager会遍历所有的AuthenticationProvider,找到能够处理UsernamePasswordAuthenticationToken的DaoAuthenticationProvider。 - DaoAuthenticationProvider认证:
DaoAuthenticationProvider会调用UserDetailsService的loadUserByUsername方法获取用户信息,然后使用PasswordEncoder对比密码。 - 认证成功或失败:
- 如果密码正确,
DaoAuthenticationProvider会创建一个新的Authentication对象,包含用户的权限信息,返回给AuthenticationManager。 - 如果密码不正确,会抛出
BadCredentialsException异常。
- 如果密码正确,
- SecurityContextHolder设置认证信息:认证成功后,
AuthenticationManager会将认证信息设置到SecurityContextHolder中。 - 用户登录成功:用户登录成功后,就可以访问系统资源了。
5.2 代码实现
相信通过上面流程图,大家对认证流程已经很清楚了。
下面我们看看怎么把用户存入内存中,我们参照官方给出的实例即可
https://docs.spring.io/spring-security/reference/servlet/configuration/java.html
①创建一个WebSecurityConfig配置类:
②然后定义一个@Bean,类型是UserDetailsService,实现是InMemoryUserDetailsManager
具体代码如下
@Configuration //标明这个类为配置类,spring应用程序一启动,类中的been 就会被初始化在spring容器中
@EnableWebSecurity //开启spring security 自定义配置
public class WebSecurityConfig {
@Bean
public UserDetailsService userDetailsService(){
//1、创建基于内存的用户管理器
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
// 3、将第二步创建的UserDetail对象交给UserDetailsManager 管理
inMemoryUserDetailsManager.createUser(
//2、创建UserDetail 对象,用于管理用户名、用户密码、用户角色、用户权限
//下面代码创建了一个用户名为user,密码为123456,角色为user的用户对象
User.withDefaultPasswordEncoder()
.username("user")
.password("123456")
.roles("user")
.build());
return inMemoryUserDetailsManager;
}
}
通过上面配置类,在程序启动的时候。就会将用户名:user 密码:123456 角色:user这样一个用户存入内存中。
当用户想要获取资源时,就会走5.1小节认证流程。
六、小结
通过这篇的学习,我们知道了SpringSecurity 默认为我们干了些啥?基于内存的认证是怎么实现的?
当然了,实际开发中,我们不可能把用户存于内存中,而是需要将用户存于数据库中。通过数据库获取用户和权限信息。
由于文章篇幅原因,这篇就到这儿了。下一篇我们来看看实际开发中,怎么基于数据库进行认证。
SpringBoot3整合SpringSecurity6(二)SpringSecurity默默的干了些啥的更多相关文章
- SpringBoot3.0 + SpringSecurity6.0+JWT
JWT_SpringSecurity SpringBoot3.0 + SpringSecurity6.0+JWT Spring Security 是 Spring 家族中的一个安全管理框架. 一般We ...
- Android app启动activity并调用onCreate()方法时都默默地干了什么?
Android app启动activity并调用onCreate() 方法时都默默地干了什么? 在AndroidManifest.xml文件中的<intent-filter>元素中有这 ...
- swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?
date: 2018-8-01 14:22:17title: swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?description: 阅读 sowft 框架源码, 了解 sowf ...
- Netty学习——Netty和Protobuf的整合(二)
Netty学习——Netty和Protobuf的整合(二) 这程序是有瑕疵的,解码器那里不通用,耦合性太强,有两个很明显的问题,但是要怎么解决呢?如:再加一个内部类型 Person2,之前的代码就不能 ...
- Springboot3整合使用ja-captcha行为验证码解决方案
截止到目前,Springboot最新稳定版本已经迭代到3.0.5,而我们项目中使用的行为验证码框架ja-captcha还没有适配Springboot3,码云上类似的请求也没有得到过回应,于是决定自己动 ...
- loadView在App启动时到底都干了些什么?
loadView在App启动时到底都干了些什么? 查阅苹果官方文档如下: 1. 当你访问一个ViewController的view属性时,如果此时view的值是nil,那么,ViewControlle ...
- Beagleboneblack的MLO文件干了些啥
Beagleboneblack在启动linux之前还有三个启动阶段: ROM code --> MLO --> u-boot --> kernel 先看看ROM code干了 ...
- 输入url后浏览器干了些什么(详解)
输入url后浏览器干了些什么(详解) DNS(Domain Name System, 域名系统) 解析 DNS解析的过程就是寻找哪台机器上有你真正需要的资源过程.但你在浏览器张红输入一个地址时,例如: ...
- 008-shiro与spring web项目整合【二】认证、授权、session管理
一.认证 1.添加凭证匹配器 添加凭证匹配器实现md5加密校验. 修改applicationContext-shiro.xml: <!-- realm --> <bean id=&q ...
- SSM整合学习 二
二:与Spring MVC整合 一:添加Spring MVC Framework 右键项目名称,点击Add Framework Support 选择Spring-Spring MVC框架 选择Down ...
随机推荐
- linxu7下安装pacemaker+corosync集群-01
1.yum仓库的配置-自行配置 2.安装软件包: yum -y install pacemaker* corosync* pcs* psmisc yum -y install pcs fence-ag ...
- Luogu P11553 ROIR 2016 Day 1 奇怪的字符串 题解 [ 绿 ] [ 后缀自动机 ] [ 枚举 ] [ 观察 ]
奇怪的字符串:需要一点观察的 SAM 小清新题. 观察 我们首先观察什么样的字符串才是奇怪的,可以发现,首先类似 AAAAAAA 之类全部相等的字符串是奇怪的. 继续观察,如果字符种类变为两种或者三种 ...
- NOI春季测试游记
Day -20 本来以为不能报名,但听说初中生可以报名,遂报名. Day -20~-2 刷一些题,并学了大量新知识如DP. Day n(-15≤n≤-5) 在公众号的名单上看到我的名字. 同校还有人参 ...
- [PA2021] Od deski do deski 题解
好题好题,难者不会会者不难,我是前者. 实际上加入就可以合法的数是很好计算的.考虑现在所有前缀合法串后的字符实际上都可以满足条件. 容易想到根据是否合法设置状态.设 \(f_{i,j}/g_{i,j} ...
- 微信小程序之java服务端获取openid
微信小程序越来越热,最近团队写了一个小程序,这篇博客我将讲一下怎么通过java服务端获取到用户的openid. api文档的授权登陆地址: http://developers.weixin.qq.co ...
- Java中编译期异常和运行期异常的区别
在Java中,异常分为运行期异常(Runtime Exception)和编译期异常(Checked Exception),两者的核心区别在于 编译器是否强制要求处理.以下是它们的详细对比: 1. 定义 ...
- QT5笔记:11. Qt类库的模块
基础模块:提供了Qt的最基本的功能 附加模块:实现了一些特定功能的提供了附加价值的模块 增值模块:商业版才有的模块,单独发布的提供额外附加价值的模块或工具 技术预览模块:一些处于开发阶段,但是可以作为 ...
- MySQL - [20] 事务
题记部分 一.什么是ACID (1)Atomicity 原子性 某个操作,要么全部执行完毕,要么全部回滚. (2)Consistency 一致性 数据库中的数据全都符合现实世界中的约束,则这些数据就符 ...
- 借Processing语言及IDE做DOS批处理的事务( 批量修改文件夹或文件的名字 )
一直想用Processing语言做一些批处理的事务,因为其自带的IDE功能紧凑易用,极度轻量,又加上Java语言的生态极具友好,处理一些windows相关操作完全可行,简单快捷. 这次就是用它做[批量 ...
- Springboot 在项目启动时将数据缓存到全局变量
有写字典数据不会频繁更新,但是会频繁查询,想要减少数据库链接次数,把内容缓存到项目的全局变量中,提高方法查询速度 import javax.annotation.PostConstruct; impo ...