SpringSecurity框架学习与使用
SpringSecurity框架学习与使用
- SpringSecurity学习
- SpringSecurity入门
- SpringSecurity深入
- 认证
- 授权
- 自定义授权失败页面
- 权限注解
- @Secured
- @PreAuthorize
- @PostAuthorize
- @PostFilter
- @PreFilter
- 参考
SpringSecurity学习
SpringSecurity入门
引入相关的依赖,SpringBoot的版本是2.7.10;
<dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity6</artifactId><version>3.1.1.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
前端页面编写,home.html、hello.html、login.html
hello.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
<head><title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello <span th:remove="tag" sec:authentication="name">thymeleaf</span>!</h1>
<form th:action="@{/logout}" method="post"><input type="submit" value="Sign Out"/>
</form>
</body>
</html>
home.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head><title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1><p>Click <a th:href="@{/templates/hello.html}">here</a> to see a greeting.</p>
</body>
</html>
login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head><title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">Invalid username and password.
</div>
<div th:if="${param.logout}">You have been logged out.
</div>
<form th:action="@{/login}" method="post"><div><label> User Name : <input type="text" name="username"/> </label></div><div><label> Password: <input type="password" name="password"/> </label></div><div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
视图控制,访问对应的url跳转到不同的页面
/*** 视图配置*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {WebMvcConfigurer.super.addViewControllers(registry);//请求/home时显示home.html页面registry.addViewController("/home").setViewName("home");registry.addViewController("/").setViewName("home");registry.addViewController("/hello").setViewName("hello");registry.addViewController("/login").setViewName("login");}
}
SpringSecurity配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(request -> {request.antMatchers("/").permitAll()// /home、/ 的请求可以访问.antMatchers("/home").permitAll() //除了上面的请求,其它的请求必须认证通过.anyRequest().authenticated(); })//设置登录页面以及允许访问登录页面,springSecurity是有自带的默认登录页面的,如果不 设置会跳转到默认的登录页面.formLogin((form) -> form.loginPage("/login").permitAll()) //允许访问登出页面.logout(LogoutConfigurer::permitAll);return http.build();}/*** 设置默认的登录密码,这里是直接使用存放在内存中的密码;* 实际开发从数据库中查询读取* @return*/@Beanpublic UserDetailsService userDetailsService() {UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();return new InMemoryUserDetailsManager(user);}
}
结果

登录失败时

登录成功

SpringSecurity深入
认证
上面的demo中,我们是把登录密码放在内存中记录着的,除了这种方式外我们还可以在配置文件中设置登录用户名和密码;

实际开发中一般都从数据库中进行读取;因此我们需要实现UserDetailsService接口,这个接口中有一个loadUserByUsername方法,我们在这个方法中根据username查询用户的信息,如果查询到了,就把用户的信息封装成UserDetails返回。

用户输入的密码会被我们注入的PasswordEncoder加密,所以在后面模拟的从数据库中查询用户密码的时候,对输入的密码使用PasswordEncoder加密了。
/*** 密码加密* @return*/@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
用户认证接口实现
@Service("userDetailService")
public class MyUserDetailServiceImpl implements UserDetailsService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//模拟从数据库中查询出密码if ("zhangsan".equals(username)) {username = "zhangsan";String password = passwordEncoder.encode("root");return new User(username, password, true, true, true, true,AuthorityUtils.commaSeparatedStringToAuthorityList("admin, ROLE_SALES"));}throw new UsernameNotFoundException("用户没有找到");}}
授权
前面我们对用户认证进行了讲解,接下来讲如何授权。
在SpringSecurity中用户认证和授权的过程是很紧密的,在loadUserByUsername方法返回的UserDetails的构造函数中最后一个参数就是用户具有的权限。而在Shiro中,授权和认证是分为两个方法的。
在SpringSecurity中我们通过AuthorizedUrl类的方法来确定访问指定的url需要的请求和角色。
| 方法 | 作用 |
|---|---|
| hasAuthority | 如果当前的主体具有指定的权限,则返回 true,否则返回 false |
| hasAnyAuthority | 如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回true |
| hasRole | 如果用户具备给定角色就允许访问,否则出现 403。如果当前主体具有指定的角色,则返回 true |
| hasAnyRole | 表示用户具备任何一个条件都可以访问 |

url:/test/test1,只有SALES角色才能访问;
url:/test/test2,只有admin权限才能访问;
@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(request -> {request.antMatchers("/").permitAll().antMatchers("/home").permitAll() // /home、/ 的请求可以访问//需要SALES角色才可以访问.antMatchers("/test/test1").hasRole("SALES")//需要admin权限才能访问.antMatchers("/test/test2").hasAuthority("admin").anyRequest().authenticated(); //除了上面的,其它的请求必须认证通过}).formLogin((form) -> form.loginPage("/login").permitAll()) //设置登录页面以及允许访问登录页面.logout(LogoutConfigurer::permitAll);return http.build();}
自定义授权失败页面
@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(request -> {request.antMatchers("/").permitAll().antMatchers("/home").permitAll() // /home、/ 的请求可以访问.antMatchers("/test/test1").hasRole("SALES").antMatchers("/test/test2").hasAuthority("admin").anyRequest().authenticated(); //除了上面的,其它的请求必须认证通过});//设置没有权限访问跳转自定义页面http.exceptionHandling().accessDeniedPage("/error.html");http.formLogin((form) -> {//设置登录页面以及允许访问登录页面form.loginPage("/login").permitAll()//登录访问路径.loginProcessingUrl("/login")//登录成功之后的跳转路径.defaultSuccessUrl("/hello").permitAll(); }).logout(LogoutConfigurer::permitAll);return http.build();}
权限注解
| 注解 | 作用 |
|---|---|
| @Secured | 判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_ |
| @PreAuthorize | 注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用户的 roles/permissions 参数传到方法中 |
| @PostAuthorize | 在方法执行后再进行权限验证,适合验证带有返回值的权限 |
| @PostFilter | 权限验证之后对数据进行过滤 留下用户名是 admin1 的数据 |
@Secured
@Secured:判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“
使用@Secured注解之前需要先使用注解@EnableGlobalMethodSecurity(securedEnabled=true)开启此功能;
@RequestMapping("testSecured")
@ResponseBody
@Secured({"ROLE_normal","ROLE_admin"}) //判断是否有normal、admin角色
public String helloUser() {
return "hello,user";
}
@PreAuthorize
@PreAuthorize:注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用户的 roles/permissions 参数传到方法中;同样的使用之前也需要使用@EnableGlobalMethodSecurity(prePostEnabled = true)开启此功能;
@RequestMapping("/preAuthorize")
@ResponseBody
@PreAuthorize("hasAnyAuthority('menu:system')")
public String preAuthorize(){System.out.println("preAuthorize");
return "preAuthorize";
}
@PostAuthorize
@PostAuthorize:在方法执行后再进行权限验证,适合验证带有返回值的权限;
@RequestMapping("/testPostAuthorize")
@ResponseBody
@PostAuthorize("hasAnyAuthority('menu:system')")
public String preAuthorize(){
System.out.println("test--PostAuthorize");
return "PostAuthorize";
}
@PostFilter
@PostFilter :权限验证之后对数据进行过滤 留下用户名是 admin1 的数据;
表达式中的 filterObject 引用的是方法返回值 List 中的某一个元素;
@RequestMapping("getAll")
@PreAuthorize("hasRole('ROLE_管理员')")
@PostFilter("filterObject.username == 'admin1'")
@ResponseBody
public List<UserInfo> getAllUser(){ArrayList<UserInfo> list = new ArrayList<>();list.add(new UserInfo(1l,"admin1","6666"));list.add(new UserInfo(2l,"admin2","888"));
return list;
}
@PreFilter
@PreFilter: 进入控制器之前对数据进行过滤
@RequestMapping("getTestPreFilter")
@PreAuthorize("hasRole('ROLE_管理员')")
@PreFilter(value = "filterObject.id%2==0")
@ResponseBody
public List<UserInfo> getTestPreFilter(@RequestBody List<UserInfo>
list){list.forEach(t-> {System.out.println(t.getId()+"\t"+t.getUsername());});
return list;
}
除了上面提到的注解外,还有权限表达式,权限表达式
参考
- SpringSecurity视频
- SpringSecurity教程
- SpringSecurity文档
相关文章:
SpringSecurity框架学习与使用
SpringSecurity框架学习与使用 SpringSecurity学习SpringSecurity入门SpringSecurity深入认证授权自定义授权失败页面权限注解SecuredPreAuthorizePostAuthorizePostFilterPreFilter 参考 SpringSecurity学习 SpringSecurity入门 引入相关的依赖,SpringBoot的版本…...
DHCP+链路聚合+NAT+ACL小型实验
实验要求: 1.按照拓扑图上标识规划网络。 2.使用0SPF协议进程100实现ISP互通。 3.私网内PC属于VLAN1O, FTP Server属于VLAN2O,网关分 别为所连接的接入交换机,其中PC要求通过DHCP动态获取 4:私网内部所有交换机都为三层交换机,请合理规划VLAN&#…...
西瓜书读书笔记整理(三)—— 第二章 模型评估与选择
第二章 模型评估与选择 第 2 章 模型评估与选择2.1 经验误差与过拟合1. 错误率 / 精度 / 误差2. 训练误差 / 经验误差 / 泛化误差3. 过拟合 / 欠拟合4. 学习能力5. 模型选择 2.2 评估方法1. 评估方法概述2. 留出法3. 交叉验证法4. 自助法5. 调参 / 最终模型 2.3 性能度量1. 回归…...
AcWing算法提高课-1.3.6货币系统
宣传一下算法提高课整理 <— CSDN个人主页:更好的阅读体验 <— 本题链接(AcWing) 点这里 题目描述 给你一个n种面值的货币系统,求组成面值为m的货币有多少种方案。 输入格式 第一行,包含两个整数n和m。 接…...
vue3回到上一个路由页面
学习链接 Vue Router获取当前页面由哪个路由跳转 在Vue3的setup中如何使用this beforeRouteEnter 在这个路由方法中不能访问到组件实例this,但是可以使用next里面的vm访问到组件实例,并通过vm.$data获取组件实例上的data数据getCurrentInstance 是vue3提…...
Linux三种网络模式 | 仅主机、桥接、NAT
💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Linux三种网络模式 仅主机模式:虚拟机只能访问物理机,不能上网 桥接模式:虚拟机和物理机连接同一网络,虚拟机和物理机…...
数据库设计与前端框架
数据库设计与前端框架 学习目标: 理解多租户的数据库设计方案 熟练使用PowerDesigner构建数据库模型理解前端工程的基本架构和执行流程 完成前端工程企业模块开发 多租户SaaS平台的数据库方案 多租户是什么 多租户技术(Multi-TenancyTechnology&a…...
技术探秘:揭秘Bean Factory与FactoryBean的区别!
大家好,我是小米,一个热衷于技术分享的29岁小编。今天,我们来聊一聊在Spring框架中常用的两个概念:beanFactory和FactoryBean。它们虽然看似相似,但实际上有着不同的用途和作用。让我们一起来揭开它们的神秘面纱吧&…...
MD-MTSP:遗传算法GA求解多仓库多旅行商问题(提供MATLAB代码,可以修改旅行商个数及起点)
一、多仓库多旅行商问题 多旅行商问题(Multiple Traveling Salesman Problem, MTSP)是著名的旅行商问题(Traveling Salesman Problem, TSP)的延伸,多旅行商问题定义为:给定一个𝑛座城市的城市集…...
技术面试的终极指南:助你取得成功的关键步骤
背景 技术面试是许多求职者最关键的一环,因为它评估了你在特定领域的知识和技能。无论你是刚毕业的大学应届生,还是有多年工作经验的职场老兵,准备充分是成功面试的关键。 这篇文章将提供一系列关键步骤,帮助你充分准备和展现自己…...
Nautilus Chain 测试网第二阶段,推出忠诚度计划及广泛空投
随着更多的公链底层面向市场,通过参与早期测试在主网上线后获得激励成为了行业的一个热点话题,在 Apots、Arbitrum One、Optimism等陆续发放了测试空投后,以 Layer3为主要特性的 Nautilus Chain 也在前不久明确表示将会有空投,引发…...
Python爬虫(三):BeautifulSoup库
BeautifulSoup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库,它能够将 HTML 或 XML 转化为可定位的树形结构,并提供了导航、查找、修改功能,它会自动将输入文档转换为 Unicode 编码,输出文档转换为 UTF-8 编码。 Beauti…...
Python使用CV2库捕获、播放和保存摄像头视频
Python使用CV2库捕获、播放和保存摄像头视频 特别提示:CV2指的是OpenCV2(Open Source Computer Vision Library),安装的时候是 opencv_python,但在导入的时候采用 import cv2。 若想使用cv2库必须先安装,P…...
[数据结构 -- C语言] 栈(Stack)
目录 1、栈 1.1 栈的概念及结构 2、栈的实现 2.1 接口 3、接口的实现 3.1 初始化 3.2 入栈/压栈 3.3 出栈 3.4 获取栈顶元素 3.5 获取栈中有效元素个数 3.6.1 bool 类型接口 3.6.2 int 类型接口 3.7 销毁栈 4、完整代码 5、功能测试 1、栈 1.1 栈的概念及结构 …...
【我的C++入门之旅】(上)
前言 C的发展史 1979年,贝尔实验室的Bjarne等人试图分析unix内核的时候,试图将内核模块化,但是发现C语言有很多的不足之处,于是在C语言的基础上进行扩展,增加了类的机制,完成了一个可以运行的预处理程序&…...
dcdc降压电路原理及仿真
在之前的文章 DCDC 降压芯片基本原理及选型主要参数介绍 中已经大致讲解了dcdc降压电路的工作原理,今天再结合仿真将buck电路工作过程讲一讲。 基本拓扑 上图为buck电路的基本拓扑结构,开关打到1,电感充电;开关打到0,…...
搭建Redis主从集群+哨兵+代理predixy
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、Redis是什么?二、搭建Redis集群步骤1.环境和版本2.Redis 安装部署3.主从同步配置4.哨兵模式配置5.代理predixy配置 总结 前言 提示:…...
Syncthing文件同步 - 免费搭建开源的文件自动同步服务器并公网远程访问【私人云盘】
文章目录 1. 前言2. Syncthing网站搭建2.1 Syncthing下载和安装2.2 Syncthing网页测试2.3 注册安装cpolar内网穿透 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 在数据爆炸的当下,每天都会产生海量的数据,这些…...
SQL——索引
💡 索引 在关系型数据库中,索引是一种单独的、物理上的对数据库表中的一列或多列的值进行排序的一种存储结构,他是某个表中的一列或着若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单(类似于图书目录&#x…...
Java代码组成部分
一、构造函数与默认构造函数 构造函数,是一种特殊方法。主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。 /** * 矩形 */ class Rectangle {/*** 构造函数*/public Rectangle(int leng…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...
