一文入门SpringSecurity 5
目录
提示
Apache Shiro和Spring Security
认证和授权
RBAC
Demo
环境
Controller
引入Spring Security
初探Security原理
认证授权图示编辑
图中涉及的类和接口
流程总结
提示
Spring Security源码的接口名和方法名都很长,看源码的时候要见名知意,有必要细看接口名和方法名,另外可以借助流程图,调试追踪代码,有助于理解学习!
Apache Shiro和Spring Security
Spring Security是一个可高度可定制的身份验证(认证)和访问控制(授权)框架,它是用于保护基于Spring的应用程序的实际标准,相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。
- Shiro轻量级,不依赖Spring,是第三方框架,简单而灵活,可以用于非Web环境!
- Security重量级,依赖Spring,控制粒度更细,老版本不能脱离Web,新版本可以
- Spring Boot 2默认使用Security 5,要求JDK至少是8
- Spring Boot 3默认使用Security 6,要求JDK至少是17
- Security 5和Security 6的区别之一就是5到6废弃了WebSecurityConfigurerAdapter类,在Security 5编写配置类需要继承WebSecurityConfigurerAdapter并重写某些方法,但是在Security 6已经不需要了
Spring Security:升级已弃用的 WebSecurityConfigurerAdapter - spring 中文网
从 Spring Security 5 迁移到 Spring Security 6/Spring Boot 3 - spring 中文网
认证和授权
认证(Authentication):验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户
授权(Authorization):经过认证后判断当前用户是否有权限进行某个操作
注:Authentication和Authorization拼写很像,有必要分清,后面看源代码方便!
RBAC
Role-Based Access Control 基于角色的访问控制
把权限打包给角色(角色拥有一组权限),给用户分配角色(用户拥有多个角色)
最少包括五张表 (用户表、角色表、用户角色表、权限表、角色权限表)
Demo
环境
Spring Boot:2.7.2
SpringSecurity:5+
JDK:1.8
Controller
@RestController
@RequestMapping("/admin")
public class AdminController {@GetMapping("/query")public String queryInfo(){return "I am a admin";}
}
可以直接访问
引入Spring Security
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
再次访问时默认出现了该登陆界面,默认用户是user,密码默认在控制台生成 ,成功登陆后才会放行。Spring Security默认拦截了除登录、退出之外的所有请求。显示的登录和退出表单是Security默认生成的。
(前端页面样式bootstrap.min.css是一个CDN地址,需要魔法,所以加载很慢)
初探Security原理
Spring Security底层是基于Servlet的过滤器链,默认共有16个过滤器,这里面我们只需要重点关注两个过滤器即可:UsernamePasswordAuthenticationFilter
负责登录认证,FilterSecurityInterceptor
负责权限授权。
认证授权图示
图中涉及的类和接口
UsernamePasswordAuthenticationFilter类
抽象类AbstractAuthenticationProcessingFilter的子类,是常用的用户名和密码认证方式的主要处理类,该类中将用请求信息封装为初步的Authentication(Authentication实际上是一个接口,它的实现类是UsernamePasswordAuthenticationToken),此时最多只有用户名和密码,在登录认证成功之后又会生成一个包含用户权限等信息的更全面的 Authentication 对象,然后把它保存在 SecurityContextHolder 所持有的 SecurityContext 中。
AuthenticationManager接口
public interface AuthenticationManager {Authentication authenticate(Authentication authentication) throws AuthenticationException; }
用来处理Authentication请求的接口。在其中只定义了一个方法 authenticate(),该方法只接收一个代表认证请求的 Authentication 对象作为参数,如果认证成功,则会返回一个封装了当前用户权限等信息的 Authentication 对象。
ProviderManager类
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean
AuthenticationManager接口的实现类,AuthenticationManager接口不直接自己处理认证请求,而是委托给ProviderManager所配置的AuthenticationProvider 列表,而ProviderManager的作用就是管理这个AuthenticationProvider列表,管理的方式是通过for循环去遍历该列表,因为不同的登录逻辑(表单登录、qq登录、邮箱登录)是不一样的,那么AuthenticationProvider列表就要支持不同的Authentication。
信息验证的逻辑都是在AuthenticationProvider里面,会依次使用每一个 AuthenticationProvider 进行认证,如果有一个 AuthenticationProvider 认证后的结果不为 null,则表示该 AuthenticationProvider 已经认证成功,之后的 AuthenticationProvider 将不再继续认证。然后直接以该 AuthenticationProvider 的认证结果作为 ProviderManager 的认证结果。如果所有的 AuthenticationProvider 的认证结果都为 null,则表示认证失败,将抛出一个 ProviderNotFoundException。AuthenticationProvider接口
该接口被实现为抽象类AbstractUserDetailsAuthenticationProvider,然后DaoAuthenticationProvider类继承该抽象类,并拥有一个UserDetailsService的变量public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAwarepublic class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider
- UserDetailsService接口
加载用户数据的核心接口,可以自定义从数据库加载数据或者从内存加载临时用户(InMemory),登录认证的时候 Spring Security 会通过 UserDetailsService 的 loadUserByUsername() 方法获取对应的 UserDetails 类型的用户信息进行认证,认证通过后会将用户信息封装为UserDetails接口的实现类User并赋给认证通过的 Authentication 的 principal,然后再把该 Authentication 存入到 SecurityContext 中。public interface UserDetailsService {UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; }
InMemoryUserDetailsManager类
该类是UserDetailsService接口的实现类,作用是从内存中加载用户,也就是说用户是在代码中提前写好的,程序运行后被加载到内存,不是从数据库中取的没有持久化,如果是从数据库加载用户就不用这个类了。该类有一个方法是private User createUserDetails(String name, UserAttribute attr),返回值是User类型
UserDetails接口
public interface UserDetails extends Serializable
提供用户核心信息的接口,通过 UserDetailsService 的 loadUserByUsername() 方法获取,然后将该 UserDetails 赋给认证通过的 Authentication 的 principal。
User类
public class User implements UserDetails, CredentialsContainer
UserDetails接口的实现类,User类也是security的默认用户类,我们可以继承该类对其方法重写
SecurityContextHolder类
用来保存 SecurityContext 的,SecurityContext 中含有当前正在访问系统的用户的详细信息。默认情况下,SecurityContextHolder 使用 ThreadLocal 来保存 SecurityContext,这也就意味着在处于同一线程中的方法中我们可以从 ThreadLocal 中获取到当前的 SecurityContext。因为线程池的原因,如果我们每次在请求完成后都将 ThreadLocal 进行清除的话,那么我们把 SecurityContext 存放在 ThreadLocal 中还是比较安全的。这些工作 Spring Security 已经自动为我们做了,即在每一次 request 结束后都将清除当前线程的 ThreadLocal。
流程总结
用户填写的用户名密码传到后端,进入Security的过滤器链进行验证,验证流程为:
进入UsernamePasswordAuthenticationFilter,里面有一个attemptAuthentication方法,该方法会生成一个UsernamePasswordAuthenticationToken,也就是一个凭证Authentication,这个Authentication只包含了用户名、密码这些基础信息,没有权限等其他信息,然后Authentication作为参数被传到AuthenticationManager接口的实现类ProviderManager类的authenticate方法进行认证,ProviderManager类中有一个List<AuthenticationProvider> 列表(AuthenticationProvider是接口,AbstractUserDetailsAuthenticationProvider是接口的抽象类,DaoAuthenticationProvider是实现类),该列表存放着不同的登录逻辑AuthenticationProvider,通过for循环去遍历该列表,信息验证的逻辑都是在AuthenticationProvider里面,会依次使用每一AuthenticationProvider进行认证,如果有一个 AuthenticationProvider 认证后的结果不为 null,则表示该AuthenticationProvider已经认证成功,之后的 AuthenticationProvider 将不再继续认证。然后直接以该 AuthenticationProvider 的认证结果作为 ProviderManager 的认证结果。如果所有的 AuthenticationProvider 的认证结果都为 null,则表示认证失败,将抛出一个 ProviderNotFoundException。
DaoAuthenticationProvider内部的认证逻辑:它有一个retrieveUser方法,该方法调用UserDetailsService().loadUserByUsername从数据库获取用户信息,并返回一个UserDetails类型的对象,它含有用户的详细信息,如用户权限等等,然后将UserDetails对象和Authentication校验,成功后会把UserDetails中的信息填入到Authentication,一个最终的Authentication就产生了,它会被保存到安全上下文中!
相关文章:

一文入门SpringSecurity 5
目录 提示 Apache Shiro和Spring Security 认证和授权 RBAC Demo 环境 Controller 引入Spring Security 初探Security原理 认证授权图示编辑 图中涉及的类和接口 流程总结 提示 Spring Security源码的接口名和方法名都很长,看源码的时候要见名知意&am…...

IPython的HTML魔法:%%html_header命令全解析
IPython的HTML魔法:%%html_header命令全解析 在IPython和Jupyter Notebook中,%%html_header是一个魔术命令,它允许用户在Notebook的单元格中添加HTML头部(head)内容。这个功能特别有用,当你需要定制Notebo…...

将SQL中的占位符替换成参数
将SQL中的占位符替换成参数 描述 描述 此方法是将SQL中的${}或#{}替换为直接拼接到SQL中或直接替换为?的形式。具体详情看下面代码。 import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern;/*** author HuYu* date 2023-09-21* since 1.0**…...

锁相环 vivado FPGA
原理 同步状态/跟踪状态:相位差在2kπ附近,频率差为0到达上述状态的过程称为捕获过程锁相环的捕获带:delta w的最大值,大于这个值的话就不能捕获鉴相器(PD-phase discriminator):相乘加LPF&…...

英语科技写作 希拉里·格拉斯曼-蒂(英文版)pdf下载
下载链接: 链接1:https://pan.baidu.com 链接2:/s/1fxRUGnlJrKEzQVF6k1GmBA 提取码:b69t 由于是英文版,可能有些看着不太方便,可以在网页版使用以下软件中英文对照着看,看着更舒服,…...

《Dynamic Statistical Learning in Massive Datastreams》论文阅读笔记
论文地址: https://www3.stat.sinica.edu.tw/ss_newpaper/SS-2023-0195_na.pdf 论文题目翻译:《在大规模数据流中的动态统计学习》 核心观点: 动态跟踪和筛选框架(DTS):论文提出了一个在线学习和模型更新的新框架&…...

【数据分享】2008-2022年我国省市县三级的逐日NO2数据(excel\shp格式)
空气质量数据是在我们日常研究中经常使用的数据!之前我们给大家分享了2000-2022年的省市县三级的逐日PM2.5数据、2013-2022年的省市县三级的逐日CO数据和2013-2022年的省市县三级的逐日SO2数据(均可查看之前的文章获悉详情)! 本次…...

JavaEE (1)
web开发概述 所谓web开发,指的是从网页中向后端程序发送请求,与后端程序进行 交互. 流程图如下 Web服务器是指驻留于因特网上某种类型计算机的程序. 可以向浏览器等Web客户端提供文档,也可以放置网站文件,让全世界浏览; 它是一个容器&…...

事务、函数和索引
什么是事务? 事务(Transaction),就是将一组SQL语句放在同一批次内去执行,如果一个SQL语句出错,则该批次内 的所有SQL都将被取消执行。 特点 一个事务中如果有一个数据库操作失败,那么整个事务…...

Android APP 基于RecyclerView框架工程(知识体系积累)
说明:这个简单的基于RecyclerView的框架作用在于自己可以将平时积累的一些有效demo整合起来(比如音视频编解码的、opengles的以及其他也去方向的、随着项目增多,工程量的增加,后期想高效的分析和查找并不容易)…...

【iOS】GCD
参考文章:GCD函数和队列原理探索 之前写项目的时候,进行耗时的网络请求使用GCD处理过异步请求,但对一些概念都很模糊,这次就来系统学习一下GCD相关 相关概念 什么是GCD? Grand Center Dispatch简称GCD,是…...

C语言 | Leetcode C语言题解之第282题给表达式添加运算符
题目: 题解: #define MAX_COUNT 10000 // 解的个数足够大 #define NUM_COUNT 100 // 操作数的个数足够大 long long num[NUM_COUNT] {0};long long calc(char *a) { // 计算表达式a的值// 将数字和符号,入栈memset(num, 0, sizeof(num));in…...

如何使用 API list 极狐GitLab 容器镜像仓库中的 tag?
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署…...

粒子群算法PSO优化BP神经网络(PSO-BP)回归预测——Python和MATLAB实现
下面是一个使用Python实现的粒子群算法(PSO)优化反向传播神经网络(BP)的示例代码。 以下是具体的代码实现: python import numpy as np from sklearn.datasets import make_regression from sklearn.model_selection…...

React-router路由配置及跳转
1、V6对比V5的修改内容 1、API: useNavigate 代替了useHistory 。 2、废弃了Route组件的exact属性。 3、组件 <Routes>代替了<Switch> 4、组件NavLink中移除了 activeStyle activeClassName 属性。 2、安装依赖react-router-dom npm install react-router-dom…...

vue3【实战】可编辑的脱敏信息
<script lang"ts" setup> import { ref, onMounted } from "vue"; let real_name ref("朝阳");let name ref("");onMounted(() > {name.value des_name(real_name.value); });function focusing() {name.value real_name…...

S71200 - 笔记
1 S71200 0 ProfiNet - 2 PLC编程 01.如何零基础快速上手S7-1200_哔哩哔哩_bilibili 西门子S7-1200PLC编程设计学习视频,从入门开始讲解_哔哩哔哩_bilibili...

linux系统查历史cpu使用数据(使用sar 查询cpu和网络占用最近1个月历史数据)。
一 sar 指令介绍 在 Linux 系统中,sar 是 System Activity Reporter 的缩写,是一个用于收集、报告和保存系统活动信息的工具。它是 sysstat 软件包的一部分,提供了丰富的系统性能数据,包括 CPU、内存、网络、磁盘等使用情况&am…...

Edge浏览器加载ActiveX控件
背景介绍 新版Edge浏览器也是采用Chromium内核,虽然没有谷歌浏览器市场占有率高,但是依托微软操作系统的优势,Edge浏览器还是发展很强劲,占据着市场第二的位置。随着微软停止服务IE浏览器,曾经风光无限的IE浏览器页退出…...

BUG与测试用例设计
一.软件测试的生命周期 需求分析→测试计划→测试设计,测试开发→测试执行→测试评估→上线→运行维护 二.BUG 1.bug的概念 (1)当且仅当规格说明(需求文档)是存在的并且正确,程序与规格说明之间的不匹配才是错误. (2)当需求规格说明书没有提到的功能,判断标准以最终用户为准…...

怎么在使用select2时,覆盖layui的下拉框样式
目录 1.覆盖下拉框样式代码 2.自定义样式 3.样式使用 1.覆盖下拉框样式代码 .layui-form-select .layui-select-title {border: none !important; /* 去除边框 */background-color: transparent !important; /* 去除背景色 */display: none;/* 其他你想要覆盖的样式 */} 2.自…...

MacOSM1 配置Miniconda环境,并设置自启动
文章目录 设置环境变量设置自启动参考 设置环境变量 cd vim .zshrc输入一下内容 # 配置Conda CONDA_HOME/Users/hanliqiang/miniconda3 PATH$CONDA_HOME/bin:$PATH生效配置 source .zshrc设置自启动 conda init zsh.zshrc 文件中将会出现以下内容 # >>> conda i…...

poi库简单使用(java如何实现动态替换模板Word内容)
目录 Blue留言: Blue的推荐: 什么是poi库? 实现动态替换 第一步:依赖 第二步:实现word模板中替换文字 模板word: 通过以下代码:(自己建一个类,随意取名…...

机器人开源调度系统OpenTcs6二开-车辆表定义
前面已经知道opentcs 需要车辆的模型结构数据,将里面的数据结构化,已表的形式生成,再找一个开源的基础框架项目对车辆进行增删改的管理 表结构: CREATE TABLE Vehicle (id INT AUTO_INCREMENT PRIMARY KEY COMMENT 唯一标识符,n…...

麦歌恩MT6521-第三代汽车磁性角度传感器芯片
磁性编码芯片 -在线编程角度位置IC 描述: MT6521是麦歌恩微电子推出的新一代基于水平霍尔及聚磁片(IMC)技术原理的磁性角度和位置检测传感器芯片。该芯片内部包含了两对互成90放置的水平霍尔阵列及聚磁片,能够根据不同的型号配置来实现对XY࿰…...

【数据结构】堆,优先级队列
目录 堆堆的性质大根堆的模拟实现接口实现构造方法建堆入堆判满删除判空获取堆顶元素 Java中的PriorityQueue实现的接口构造方法常用方法PriorityQueue注意事项 练习 堆 如果有一个集合K {k0,k1, k2,…,kn-1},把它的…...

2024 暑假友谊赛 2
Tree Queries - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路:LCA好题,也有看见用时间戳写的,不是很明白. 用LCA非常好写。 要想到,给出k个节点,要确定一条路径,使得给出的k个点要么在路径上,要么和路径中某点的…...

c++ 线程
在 C 中,std::thread 构造函数可以用于将参数传递给线程。这里是一个基本的示例,展示了如何使用 std::thread 来传递参数: #include <iostream> #include <thread>// 定义一个被线程调用的函数 void threadFunc(int arg1, doubl…...

【SpringBoot】URL映射之consumes和produces匹配、params和header匹配
4.2.3 consumes和produces匹配 //处理request Content-Type为"application/json"类型的请求 RequestMapping(value"/Content",methodRequestMethod.POST,consumes"application/json") public String Consumes(RequestBody Map param){ return…...

vscode配置django环境并创建django项目(全图文操作)
文章目录 创建项目工作路径下载python插件:创建虚拟环境1. 命令方式创建2. 图文方式创建 在虚拟环境中安装Django创建Django项目安装Django插件选择虚拟环境 创建项目工作路径 输入 code . 下载python插件: 创建虚拟环境 1. 命令方式创建 切换在工作目…...