从HelloWorld深入源码了解SpringSecurity底层逻辑

news2024/12/25 8:57:30

文章目录

  • 一、环境搭建
    • 1、创建项目测试
      • 1.1、搭建基础项目
      • 1.2、整合Spring Security
  • 二、实现原理
    • 1、Spring Security的实现原理
      • 1.1、Spring Security 如何完成认证和授权
      • 1.2、Security Filters
    • 2、 Spring Security默认配置和如何自定义配置
  • 三、整个HelloWorld的流程分析
  • 三、HelloWorld中默认⽤户⽣成
  • 三、UserDetailService
  • 四、总结

对于任何的项目都需要从一个案例来分析出其中技术的门道。 Spring Security也是这样。

一、环境搭建

对于Spring Security的环境搭建基础是Spring Boot 2.7.12

1、创建项目测试

1.1、搭建基础项目

创建一个SpringBoot项目

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.12</version>
    </parent>

为了测试方便,导入一个web项目

 <!--spring web的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

最后写上Controller的测试代码:

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        System.out.println("hello security!!");
        return "hello security";
    }
}

在这里插入图片描述
最后运行项目测试结果得到在这里插入图片描述

1.2、整合Spring Security

引入Spring Security相关依赖

  <!--spring web的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

导入成功之后,再次启动项目
在这里插入图片描述
启动完之后,控制台会生成一个密码。访问http://localhost:8080/hello,会直接跳到登录页面
在这里插入图片描述
默认的用户名是user,密码是控制台中打印的密码,输入之后可以成功进行访问。

这就是 Spring Security 的强⼤之处,只需要引⼊⼀个依赖,所有的接⼝就会⾃动保护起来!

但是有几个问题可能要解决:

  1. 为什么引⼊ Spring Security 之后没有任何配置所有请求就要认证呢?
  2. 在项⽬中明明没有登录界⾯,登录界⾯怎么来的呢?
  3. 为什么使⽤user控制台密码 能登陆,登录时验证数据源存在哪⾥呢?

二、实现原理

对于之前,如果我们要自己在Spring MVC中实现认证和授权。一般是通过下面
在这里插入图片描述
在对某一个资源进行判断当前用户是否有资格进行访问,那么我们需要在过滤器中处理逻辑操作。如果用户已经认证过并且有某一个权限就放行,否则不放行。
为啥不是拦截器?因为我们需要在访问系统资源之前来处理是否访问的需求
在这里插入图片描述

1、Spring Security的实现原理

1.1、Spring Security 如何完成认证和授权

Spring Security官方网站上有介绍https://docs.spring.io/spring-security/site/docs/5.5.4/reference/html5/#servlet-architecture,
开发者只需要引⼊⼀个依赖,就可以让 Spring Security 对应⽤进⾏保护。Spring Security ⼜是如何做到的呢?

Spring Security认证、授权 等功能都是基于过滤器完成的,从某种意义上来说,代替了我们自己手动在filter实现认证和授权的逻辑判断,交给了Spring Security来做 。
在这里插入图片描述

需要注意的是,默认过滤器并不是直接放在 Web 项⽬的原⽣过滤器链中,⽽是通过⼀个FliterChainProxy 来统⼀管理。Spring Security 中的过滤器链通过FilterChainProxy 嵌⼊到 Web项⽬的原⽣过滤器链中。FilterChainProxy 作为⼀个顶层的管理者,将统⼀管理 Security FilterFilterChainProxy 本身是通过Spring框架提供的 DelegatingFilterProxy 整合到原⽣的过滤器链中。

通俗的理解SpringSeucritySecurity Filter要整合到原生的Filter中,需要借助DelegatingFilterProxy,但是Security Filter不止一个,需要通过FilterChainProxy来管理谁先谁后,但是为了 更加灵活的进行配置,可以定义不同的FilterChain来管理一系列不同的Filter,最后的总体图如下所示:

SecurityFilterChain提供了更加灵活的配置:
在这里插入图片描述

1.2、Security Filters

那么在 Spring Security 中给我们提供那些过滤器? 默认情况下那些过滤器会被加载呢?

在官方网站https://docs.spring.io/spring-security/site/docs/5.5.4/reference/html5/#servlet-delegatingfilterproxy中有说明。

过滤器过滤器作用默认是否加载
ChannelProcessingFilter过滤请求协议 HTTP 、HTTPSNO
WebAsyncManagerIntegrationFilter将 WebAsyncManger 与 SpringSecurity 上下文进行集成YES
SecurityContextPersistenceFilter在处理请求之前,将安全信息加载到 SecurityContextHolder 中YES
HeaderWriterFilter处理头信息加入响应中YES
CorsFilter处理跨域问题NO
CsrfFilter处理 CSRF 攻击YES
LogoutFilter处理注销登录YES
OAuth2AuthorizationRequestRedirectFilter处理 OAuth2 认证重定向NO
Saml2WebSsoAuthenticationRequestFilter处理 SAML 认证NO
X509AuthenticationFilter处理 X509 认证NO
AbstractPreAuthenticatedProcessingFilter处理预认证问题NO
CasAuthenticationFilter处理 CAS 单点登录NO
OAuth2LoginAuthenticationFilter处理 OAuth2 认证NO
Saml2WebSsoAuthenticationFilter处理 SAML 认证NO
UsernamePasswordAuthenticationFilter处理表单登录YES
OpenIDAuthenticationFilter处理 OpenID 认证NO
DefaultLoginPageGeneratingFilter配置默认登录页面YES
DefaultLogoutPageGeneratingFilter配置默认注销页面YES
ConcurrentSessionFilter处理 Session 有效期NO
DigestAuthenticationFilter处理 HTTP 摘要认证NO
BearerTokenAuthenticationFilter处理 OAuth2 认证的 Access TokenNO
BasicAuthenticationFilter处理 HttpBasic 登录YES
RequestCacheAwareFilter处理请求缓存YES
SecurityContextHolder<br />AwareRequestFilter包装原始请求YES
JaasApiIntegrationFilter处理 JAAS 认证NO
RememberMeAuthenticationFilter处理 RememberMe 登录NO
AnonymousAuthenticationFilter配置匿名认证YES
OAuth2AuthorizationCodeGrantFilter处理OAuth2认证中授权码NO
SessionManagementFilter处理 session 并发问题YES
ExceptionTranslationFilter处理认证/授权中的异常YES
FilterSecurityInterceptor处理授权相关YES
SwitchUserFilter处理账户切换NO

可以看出,Spring Security 提供了 30 多个过滤器。默认情况下Spring Boot 在对Spring Security 进⼊⾃动化配置时,会创建⼀个名SpringSecurityFilerChain的过滤器,并注⼊到 Spring 容器中,这个过滤器将负责所有的安全管理,包括⽤户认证、授权、重定向到登录⻚⾯等。具体可以参考WebSecurityConfiguration的源码:
在这里插入图片描述
在这里插入图片描述

2、 Spring Security默认配置和如何自定义配置

从上文中,我们有一个问题就是:为什么引⼊ Spring Security 之后没有任何配置所有请求就要认证呢?
这就不得不提SpringBoot的默认配置类SpringBootWebSecurityConfiguration, 这个类是spring boot⾃动配置类,通过这个源码得知,默认情况下对所有请求进⾏权限控制。
在这里插入图片描述
这就是为什么在引⼊ Spring Security 中没有任何配置情况下,请求会被拦截的原因!
通过上⾯对⾃动配置分析,我们也能看出默认⽣效条件为:
在这里插入图片描述

  • 条件⼀:classpath中存在 SecurityFilterChain.class,
    HttpSecurity.class
  • 条件⼆ 没有⾃定义 WebSecurityConfigurerAdapter.class,
    SecurityFilterChain.class

默认情况下,条件都是满⾜的。WebSecurityConfigurerAdapter 这个类极其重要,
Spring Security 核⼼配置都在这个类中
在这里插入图片描述
如果要对Spring Security进⾏⾃定义配置,就要⾃定义这个类实例,通过覆盖类中⽅法达到修改默认配置的⽬的

三、整个HelloWorld的流程分析

在这里插入图片描述

  1. 请求 /hello 接⼝,在引⼊ spring security 之后会先经过⼀些列过滤器
  2. 在请求到达 FilterSecurityInterceptor时,发现请求并未认证。请求拦截下来,并抛出 AccessDeniedException 异常。
  3. 抛出 AccessDeniedException 的异常会被ExceptionTranslationFilter
    获,这个 Filter 中会调⽤ LoginUrlAuthenticationEntryPoint#commence
    ⽅法给客户端返回 302,要求客户端进⾏重定向到 /login ⻚⾯。
  4. 客户端发送/login请求。
  5. /login请求会再次被拦截器中 DefaultLoginPageGeneratingFilter 拦截到,
    并在拦截器中返回⽣成登录⻚⾯。

就是通过这种⽅式,Spring Security 默认过滤器中⽣成了登录⻚⾯,并返回!

三、HelloWorld中默认⽤户⽣成

HelloWorld中,如何通过默认的用户名和密码对用户进行登录的验证。直接通过源码来进行梳理和说明:
都是在SpringBootWebSecurityConfiguration中设置了默认情况下所有的配置都必须要认证之后才能访问系统。
SpringBootWebSecurityConfiguration#SecurityFilterChainConfiguration#defaultSecurityFilterChain方法中对所有的访问都作了限制,要求都需要进行认证。
在这里插入图片描述
那直接打开formLogin方法,发现处理登录的是FormLoginConfigurer类调用了UsernamePasswordAuthenticationFilter这个实例
在这里插入图片描述
查看类中 UsernamePasswordAuthenticationFilter#attempAuthentication得知实际调⽤ AuthenticationManager authenticate ⽅法

这里的filterSpring Security自己定义的方法,处理过滤器的主要逻辑都是在attempAuthentication

在这里插入图片描述
调⽤了 ProviderManager 实现类中AbstractUserDetailsAuthenticationProvider类中⽅法
在这里插入图片描述
直接进入到retrieveUser方法中,发现最终的用户名和密码还是从DaoAuthenticationProvider类中返回的loadUserByUsername来进行比较。
在这里插入图片描述
最后发现在InMemoryUserDetailsManager中返回的user有了用户名和密码
在这里插入图片描述
看到这⾥就知道默认实现是基于 InMemoryUserDetailsManager 这个类,也就是内存的实现!但是点开并没有自己的实现,说明是有自动配置。这个自动配置类就是UserDetailsServiceAutoConfiguration
在这里插入图片描述
以上整体的调用流程:
在这里插入图片描述

三、UserDetailService

我们知道最终要获取系统的用户名和密码的数据都需要靠UserDetails#loadUserByUsername加载出来的用户名密码来获取,但是UserDetailsService是一个接口,有很多实现类在这里插入图片描述
上述分析默认是使用InMemoryUserDetailsManager,通过UserDetailsServiceAutoConfiguration这个自动配置类来完成的,对于UserDetailsServiceAutoConfiguration的源码非常的多,这里只是对关键代码进行梳理。
在这里插入图片描述
从自动配置类的源码中得到,如果是满足一下两个条件,就会自动的将InMemoryUserDetailsManager进行配置。

  1. classpath下存在AuthenticationManager的类
  2. 当系统中没有提供AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.classAuthenticationManagerResolver.class中的任何一个类的实例

默认情况下都会满足以上两个条件,所以Spring Security会默认提供一个InMemoryUserDetailsManager的实例
在这里插入图片描述
这个实例根据SecurityProperties配置类来设置用户信息
在这里插入图片描述
这就是默认⽣成user以及 uuid 密码过程! 另外看明⽩源码之后,就知道只要在配置⽂件中加⼊如下配置可以对内存中⽤户和密码进⾏覆盖。

spring.security.user.name=fckey
spring.security.user.password=admin
spring.security.user.roles=admin,users

所以,如果想要自定义从数据库读取用户名和密码就需要自己定义一个UserDetailsService的子类,这样就不会使用InMemoryUserDetailsManager#loadUserByUsername,而是你自己定义的loadUserByUsername方法。

四、总结

对于Spring Security中的所有认证都是通过AuthenticationManager这个父类来实现的AuthenticationManagerProviderManger、以及 AuthenticationProvider关系,可以对ProviderManager或者是AuthenticationProvider来进行扩展。
在这里插入图片描述
这样子,可以通过AuthenticationProvider来完成多种登录的校验,对于AuthenticationProvider的所有实现类如下图所示:
在这里插入图片描述
还可以通过自定义WebSecurityConfigurerAdapter 扩展 Spring Security 所有默认配置
在这里插入图片描述
UserDetailService ⽤来修改默认认证的数据源信息,后期可以修改为从MyBatis,或者是JDBC来获取。
在这里插入图片描述


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

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

相关文章

流程用例的签名保障,Python接口自动化框架封装案例!

目录 前言&#xff1a; 1.项目背景及需求 2.框架整体架构设计 3.接口管理模块的封装 4.用例管理模块的封装 5.请求模块的封装 6.签名模块的封装 7.案例展示及代码实现 结语&#xff1a; 前言&#xff1a; 随着互联网技术的不断发展&#xff0c;人们对于软件质量的要求…

臻图信息跟进新基建建设,构建“智慧铁路”“指挥调度”管理系统

铁路作为国民经济的骨干、国家关键性基础建设&#xff0c;在社会经济发展中起到关键性作用&#xff0c;交通在全天运行、运量多、运价少、占地面积小和安全环保等方面有着显著的优势。 近年来&#xff0c;我国高度重视铁路发展&#xff0c;2020年8月国铁集团出台《新时代交通强…

Windows系统自带远程桌面和远程协助怎么连接?

随着IT技术的发展和远程办公的兴起&#xff0c;在日常工作中&#xff0c;远程桌面和远程协助等功能已经成为很多用户需要掌握的技能之一。而对于使用Windows系统的用户来说&#xff0c;Windows系统自带的远程桌面和远程协助功能&#xff0c;更是令人欣喜的利器。下面我们就来一…

油猴安装教程及ChatGPT配置

文章目录 目录 文章目录 前言 一. 安装油猴 二、使用步骤 三.安装插件 (ChatGPT) 四. 脚本推荐 前言 作者简介: zuiacsn 座右铭: 抱怨身处黑暗,不如提灯前行 内容介绍: 油猴 油猴&#xff08;Tampermonkey&#xff09;指的是一个流行的用户脚本管理器&#xff0c;它能使…

GAMES202作业1

目录 Shadow MapCalcLightMVP函数useShadowMap函数Bias函数 最终效果 PCF两个采样函数PCF函数最终效果 PCSSfindBlocker函数PCSS函数最终效果 参考 先放上公式&#xff1a; 后面的积分项是我们在作业0中就做好的blinnphong项&#xff0c;我们要求的就是积分项前&#xff0c;等…

认识 Protobuf 及其简单使用

文章目录 一、序列化与反序列化1.1 序列化1.2 反序列化1.3 序列化与反序列化的使用场景 二、初识 Protobuf三、Protobuf 的安装四、Protobuf 的使用案例4.1 创建并编写 .proto 文件的基本规范与语法4.2 编译 .proto 文件4.3 序列化与反序列化的使用 五、总结 ProtoBuf 的使用特…

spring boot日志

日志介绍日志的使用日志级别日志持久化更简单的输入日志lombok的运行原理 日志介绍 日志的作用&#xff1a; 1&#xff1a;发现问题&#xff1b; 2&#xff1a;定位问题&#xff1b; 3&#xff1a;记录用户的行为&#xff1a;看哪些是方法用户&#xff1b;还能拿到用户的ip&am…

【云原生|探索 Kubernetes 系列 4】理解现代云原生时代的引擎

文章目录 系列文章目录&#x1f479; 关于作者一、前言|回顾二、静态和动态视图三、爆火的容器编排工具 Kubernetes 的诞生四、Kubernetes 要解决的问题是什么&#xff1f;五、理解 Kubernetes 全局架构图Master&#xff08;控制节点&#xff09;Node&#xff08;计算节点&…

源码分析:springboot如何确定当前应用程序类型

文章目录 一、介绍二、源码分析三、测试 一、介绍 大多数java后端开发的朋友们想必都是通过创建springboot项目&#xff0c;然后通过编写Controller进行接口开发的&#xff0c;该接口底层是由非响应式的servlet提供支持的&#xff0c;其接口内部逻辑为阻塞式的。但也有一部分朋…

leetcode 837. New 21 Game(新21点)

起始点数为0&#xff0c;当手上点数 < k 时抽取新的卡片&#xff0c; 每次抽取的点数范围在 1 ~ maxPts. 每次收取是独立的&#xff0c;每个点数概率相同。 当手上点数 > k 时游戏结束。 返回手上点数 < n 的概率。 思路&#xff1a; 先看特殊情况&#xff0c; k …

JQuery实现小项目

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 目录 文章目录 一、JQuery是什么 二、JQuery项目 2.1 猜数字 2.2 表白墙 2.3 聚合搜索 2.4 计算器 一、JQuery是什么 jQuery是一个快速、简洁的JavaScript框架&#xff0c;是继Prototype之…

MQTT(1):MQTT协议介绍

随着 5G 时代的来临&#xff0c;万物物联的伟大构想正在成为现实。联网的物联网设备在 2018 年已经达到了 70 亿&#xff0c;在未来两年&#xff0c;仅智能水电气表就将超过10亿 海量的设备接入和设备管理对网络带宽、通信协议以及平台服务架构都带来了很大挑战。对于物联网协议…

pandas 遇到Key Error错误的一个小问题

最近刚刚接触Python&#xff0c;安装了Anaconda&#xff0c; 编程小白一个&#xff0c;照着教程准备做一个中考成绩录取分数线分析的案例&#xff0c; 使用read_excel()读入数据后&#xff0c; import pandas as pd data pd.read_excel(rC:\2021-2022深圳中考录取分数线(1).xl…

SpringBoot配置文件 | 多环境配置 | 读取配置的4种方式

文章目录 一、写配置文件的位置读取的优先级&#xff1a;1.文件位置&#xff1a;2.文件名和文件后缀&#xff1a;3.配置文件中的profile-specific文件&#xff1a;4.命令行参数 二、多环境配置1. properties&#xff1a;2. yaml 三、yaml配置文件yaml、properties、xml对比&…

【软考-中级】系统集成项目管理工程师 【13合同管理】

持续更新。。。。。。。。。。。。。。。 【第十三章】合同管理 2 分 考点 1考点 2考点 3考点4:成本补偿合同考点5:工料合同考点6:合同类型的选择考点 7考点 8:合同管理包括考点9考点 10考点 11考点 12考点 13考点 14考点 15历年真题2022 年 05 月2021 年 11 月2021 年 05 月 考…

Redis底层原理深入学习

一、基本类型及底层实现 1.String 1&#xff09;使用场景&#xff1a;简单字符串存储、分布式锁、计数器、全局唯一ID 2&#xff09;数据结构&#xff1a;C语言中String用char[]表示&#xff0c;源码中用SDS封装char[]&#xff0c;这是Redis存储的最小单元&#xff0c;一个SD…

安全中级3-nginx反向代理负载均衡的webshell

目录 一、负载均衡 1.nginx的负载均衡 2.nginx 支持的几种策略&#xff1a; 二、负载均衡下的webshell连接&#xff08;负载均衡下的wenbshell环境下载地址&#xff09; 1.内部网络的结构 2.场景描述 3.利用我们的中国蚁剑连接我们的代理服务器nginx 三、webshell遇到的…

电脑待机或者睡眠后TeamViewer就无法连接了

电脑待机或者睡眠后TeamViewer就无法连接了 设置睡眠状态下不关闭网卡驱动 公司的笔记本&#xff0c;安装了teamviewer&#xff0c;离开时把teamviewer打开&#xff0c;回家后连接时提示伙伴未在机器上运行&#xff0c;此时电脑处于黑屏、待机、睡眠状态 其实电脑睡眠后会关掉网…

创新管理工具:低代码平台在学校管理中的应用实践

随着信息技术的不断发展&#xff0c;学校管理也随之发生了变革。传统的学校管理方式往往是依靠人工操作&#xff0c;存在信息不透明、效率低下等问题&#xff0c;而数字化管理的出现&#xff0c;可以帮助学校提高管理效率、降低管理成本、提升数据统计和分析能力。而低代码技术…

SWAT模型教程

详情点击链接&#xff1a;SWAT模型教程详情点击链接&#xff1a;SWAT模型&#xff08;建模方法、实例应用、高级进阶&#xff09; 一&#xff1a;基于网络资源的SWAT模型快速建模​ 二&#xff1a;基于遥感产品的SWAT模型率定与验证​ 三&#xff1a;基于水文响应单元&#xff…