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…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
 
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
 
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
 
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
 
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...
CppCon 2015 学习:REFLECTION TECHNIQUES IN C++
关于 Reflection(反射) 这个概念,总结一下: Reflection(反射)是什么? 反射是对类型的自我检查能力(Introspection) 可以查看类的成员变量、成员函数等信息。反射允许枚…...
