【Spring Security】 入门实战
文章目录
- 一、基本概念
- 二、Spring Security第一个程序
- 三、Spring Security没有生效
- 四、修改默认账号密码(appliction.yml)
- 五、修改默认账号密码(配置类)
- 六、Spring Security的三个configure方法
- 七、Spring Security的三种身份的验证
一、基本概念
单点登录
- 什么叫做单点登录呢。就是在一个多应用系统中,只要在其中一个系统上登录之后,不需要在其它系统上登录也可以访问其内容。
- 举个例子,京东那么复杂的系统肯定不会是单体结构,必然是微服务架构,比如订单功能是一个系统,交易是一个系统…那么我在下订单的时候登录了,付钱难道还需要再登录一次吗,如果是这样,用户体验也太差了吧。
- 实现的流程就是我在下单的时候系统发现我没登录就让我登录,登录完了之后系统返回给我一个Token,就类似于身份证的东西;然后我想去付钱的时候就把Token再传到交易系统中,然后交易系统验证一下Token就知道是谁了,就不需要再让我登录一次。
JWT(JSON Web Token)
Token的生成与解密
RSA(非对称加密算法)
从上面的例子中可以看出,JWT在加密解密的时候都用到了同一个密钥 “ robod666 ”,这将会带来一个弊端,如果被黑客知道了密钥的内容,那么他就可以去伪造Token了。所以为了安全,我们可以使用非对称加密算法RSA。
二、Spring Security第一个程序
Spring Security导入依赖就能生效了。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
查看Controller层结果
@RestController
public class UserController {@AutowiredUserMapper userMapper;@RequestMapping("/user/select/{id}")public User list(@PathVariable("id") int id){return userMapper.queryUserById(id);}
}
启动项目,默认账号是user
,密码在输出控制信息中
在浏览器中访问localhost:8080/user/selet/2
,会自动跳转到localhost:8080/login
输入账号密码,跳转到我们原来请求的内容localhost:8080/user/selet/2
三、Spring Security没有生效
Spring Security在导入依赖之后就能生效,并且会使用一些默认配置。但是有时候导入依赖之后访问页面,也没有跳转到指定验证页面,这就是Spring Security没有生效。
这是因为,你在pom.xml中导入了依赖包,等于告诉maven要导入Spring Security依赖,但是不等于已经导入了Spring Securtiy,因为maven可能还没来得及导入,你就已经启动项目了。我们可以通过查看External Libraries
这里,看看Spring Security是否已经导入成功。
四、修改默认账号密码(appliction.yml)
在application.yml
配置文件中修改默认账号密码
启动项目,在浏览器中访问localhost:8080/user/selet/2
,会自动跳转到localhost:8080/login
,账号是nicky
,密码在123
输入账号密码,跳转到我们原来请求的内容localhost:8080/user/selet/2
五、修改默认账号密码(配置类)
也可以新建Spring Security配置类,注意Spring Security5.2.1版本,配置密码要用BCryptPasswordEncoder加密,不过登录还是明文,Spring Security不同版本各有差别,详情配置还是参考官方文档
@Configuration // 设置为配置类,变成Spring Bean
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception { //auth.inMemoryAuthentication()auth.inMemoryAuthentication().withUser("nicky").password(bcryptPasswordEncoder().encode("123456")).roles("admin").and().withUser("rocky").password(bcryptPasswordEncoder().encode("123456")).roles("admin");}@Beanpublic PasswordEncoder bcryptPasswordEncoder() {return new BCryptPasswordEncoder();}
}
启动项目,在浏览器中访问localhost:8080/user/selet/2
,会自动跳转到localhost:8080/login
,账号是nicky
,密码在123
输入账号密码,跳转到我们原来请求的内容localhost:8080/user/selet/2
六、Spring Security的三个configure方法
Spring Security通过继承WebSecurityConfigurationAdapter这个类,可以选择实现该类中的三个重载的configure方法
configure(AuthenticationManagerBuilder auth):用来记录账号,密码,角色信息。
AuthenticationManagerBuilder allows public void configure(AuthenticationManagerBuilder auth) {auth.inMemoryAuthentication().withUser("user").password("password").roles("USER").and().withUser("admin").password("password").roles("ADMIN","USER");
}
configure(HttpSecurity http):(授权)配置 URL 访问权限,对应用户的权限
protected void configure(HttpSecurity http) throws Exception {http//任何请求都必须经过身份验证.authorizeUrls().antMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated();
configure(WebSecurity):一般用于配置忽略掉的 URL 地址,一般用于js,css,图片等静态资源
public void configure(WebSecurity web) throws Exception {web//web.ignoring() 用来配置忽略掉的 URL 地址,一般用于静态文件.ignoring().antMatchers("/resources/**");
}
七、Spring Security的三种身份的验证
1. 默认身份验证
在pom.xml文件映入SpringSecutrity依赖启动器,启动项目,访问文章列表页面时,出现默认的登录页,需要用默认用户名:user,密码源于控制台输出,也就是最基础的登录
2. 内存身份验证
自定义用户名和密码(用户名和密码是写在代码内,不好维护)
@Configuration // 设置为配置类,变成Spring Bean
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("nicky").password(bcryptPasswordEncoder().encode("123456")).roles("admin").and().withUser("rocky").password(bcryptPasswordEncoder().encode("123456")).roles("admin");}@Beanpublic PasswordEncoder bcryptPasswordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.headers().frameOptions().disable();//开启运行iframe嵌套页面//任何请求都必须经过身份验证http.authorizeRequests().anyRequest().authenticated();http.authorizeRequests().antMatchers("/vip/vip0/**").hasRole("vip0").antMatchers("/vip/vip1/**").hasRole("vip1").antMatchers("/vip/vip2/**").hasRole("vip2").antMatchers("/vip/vip3/**").hasRole("vip3");//开启表单验证http.formLogin().and().formLogin()//开启表单验证.loginPage("/toLogin")//跳转到自定义的登录页面.usernameParameter("name")//自定义表单的用户名的name,默认为username.passwordParameter("pwd")//自定义表单的密码的name,默认为password.loginProcessingUrl("/doLogin")//表单请求的地址,一般与form的action属性一致.successForwardUrl("/index")//登录成功后跳转的页面(重定向).failureForwardUrl("/toLogin")//登录失败后跳转的页面(重定向).and().logout()//开启注销功能.logoutSuccessUrl("/toLogin")//注销后跳转到哪一个页面.logoutUrl("/logout") // 配置注销登录请求URL为"/logout"(默认也就是 /logout).clearAuthentication(true) // 清除身份认证信息.invalidateHttpSession(true) //使Http会话无效.permitAll() // 允许访问登录表单、登录接口.and().csrf().disable(); // 关闭csrf}
}
3. 数据库方式校验
实现WebSecurityConfigurerAdapter类:将身份校验方式改变为数据库方式校验,即使用UserDetailsService
/*开启安全管理配置*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredUserDetailsServiceImpl userDetailsService;/*自定义身份认证*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {/*1. 密码编译器*/BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();/*2.使用UserDetails进行身份认证*/auth.userDetailsService(userDetailsService).passwordEncoder(encoder);}/*自定义用户权限*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/").permitAll() // 表示放行“/”访问.antMatchers("/admin/**").hasAuthority("admin") // 表示admin才能访问/admin/**.antMatchers("/common/**").hasAuthority("common") // 表示common可以访问/commom/**.and().formLogin();}
}
实现UserDetailsService类:该类只有 loadUserByUsername 一个接口方法, 用于通过用户名获取用户数据. 返回 UserDetails 对象, 表示用户的核心信息 (用户名, 用户密码, 权限等信息).
注意:其实UserDetailsService就是一个Service层的类,没有大不了的,我们也可以用UserService继承UserDetailsService
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@AutowiredUserMapper userMapper;@AutowiredAuthorityMapper authorityMapper;/*根据前端登录页面传入的用户名,查询出数据库对应的用户信息和用户权限,把用户信息和权限封装成UserDetails对象,交给SpringSecurity进行身份认证*/@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();/*根据用户名查询用户信息*/User user = userMapper.selectUserByUserName(s);/*根据用户名查询权限信息*/List<Authority> authorities = authorityMapper.selectAuthorityByUserName(s);/*遍历封装用户权限*/List<SimpleGrantedAuthority> authorityList = new ArrayList<>();for (int i=0; i<authorities.size(); i++){authorityList.add(new SimpleGrantedAuthority(authorities.get(i).getAuthority()));}// 如果用户不存在if(user!=null){/*将用户名、密码、用户权限封装成UserDetails对象*/UserDetails userDetails = new User(user.getUsername(),encoder.encode(user.getPassword()),authorityList);return userDetails;}else {throw new UsernameNotFoundException("用户不存在");}}
}
编写UserMapper类:这里仅仅编写了Mapper层逻辑,至于domain与数据库sql就不再赘述了
@Mapper
public interface UserMapper {/*根据用户名去查询用户讯息*/
@Select("select * from t_user where username=#{username}")public TUser selectUserByUserName(String username);
}
@Mapper
public interface AuthorityMapper {/*根据用户名去查询用户权限*/@Select(" select a.* from t_user u,t_authority a,user_authority au where u.id=au.uid and a.id=au.aid and u.username=#{username}")
public List<Authority> selectAuthorityByUserName(String username);
}
相关文章:

【Spring Security】 入门实战
文章目录 一、基本概念二、Spring Security第一个程序三、Spring Security没有生效四、修改默认账号密码(appliction.yml)五、修改默认账号密码(配置类)六、Spring Security的三个configure方法七、Spring Security的三种身份的验…...

SpringBoot的Interceptor拦截器的简介和实际使用
拦截器(Interceptor) 概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。 作用:拦截请求,在指定的方法调用前后,根据业务需要执行…...

5个面向Python高级开发者的技巧
使用这些用于自定义类行为、编写并发代码、管理资源、存储和操作数据以及优化代码性能的高级技术来探索 Python 的深度。 本文探讨了 Python 中的五个高级主题,它们可以为解决问题和提高代码的可靠性和性能提供有价值的见解和技术。从允许您在定义类时自定义类行为的…...

Nginx简介
Nginx是什么?可以做什么事情? Nginx是高性能的HTTP和反向代理的web服务器,处理高并发的能力十分强大,能经受高负载的考研,有报告表明能能支持高达50000个并发连接数。 特点 占有内存少:一万个长连接&…...

十五分钟带你学会 Electron
文章目录 什么是 Electron为什么要选择 Electron安装 Electron桌面CSDN实战Electron 基础配置Electron 进程主进程渲染进程主进程与渲染进程的区别主进程与渲染进程的通信 Electron 跨平台问题Electron 部署打包应用程序发布应用程序 Electron 跨端原理总结 什么是 Electron E…...

设计模式-结构型模式之桥接模式
2. 桥接模式 2.1. 模式动机 设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案: 第一种设计方案是为每一种形状…...

软件测试工程师为什么要写测试用例?
软件测试工程师为什么要写测试用例?相信从事软件测试行业的从业者来讲,测试用例并不陌生。因为测试用例不仅仅是一组简单的文档,它包含前提条件、输入、执行条件和预期结果等等重要内容,并且能够完成一定的测试目的和需求。下面本…...

【DAY40】VUE练习
DOS命令: DOS(Disk Operating System)是一种操作系统,它使用命令行界面(Command Prompt)进行交互。在 DOS 中,有一些常用的命令,可以用来定位目录、创建、删除、拷贝文件和目录&…...

实模式的寄存器
实模式的寄存器有8个通用寄存器,分别为AX、BX、CX、DX、SI、DI、BP和SP。通用的意思就是它们之中的大部分可以根据需要用于多种目的。 AX: accumulator,累加寄存器 BX: base,基址寄存器 CX: count,计数寄存器 SI: Source Index&am…...

【UE 控件蓝图】通过键盘选中要点击的按钮 通过Enter键点击
上一篇【UE 控件蓝图】菜单及功能实现博客已经完成了菜单的制作,但是我们只能通过鼠标来点击菜单选项,本篇博客实现的是能够通过键盘的上下键来选中按钮,然后按下“Enter”键来实现点击按钮的效果。 效果 可以看到并没有移动鼠标也可以通过…...

SSR在天猫优品大促会场的探索实践
BBC 发现其网站加载时间每增加一秒,用户便会流失 10%。为提高页面的秒开率,我们不断探索着优化策略,仅仅在浏览器领域下的优化已经满足不了我们的极致要求,开始往服务端方向不断探索。本文将讨论业务接入SSR的几个问题:…...
WPF教程(一)---创建一个WPF程序基础知识
1.前言: 这篇主要讲WPF的开发基础,介绍了如何使用Visual Studio 2019创建一个WPF应用程序。 首先说一下学习WPF的基础知识: 1) 要会一门.NET所支持的编程语言--例如C#。 2) 会一点“标准通用标记语言”:WPF窗体程序使用的XAML语…...

【C++ 四】函数、指针
函数、指针 文章目录 函数、指针前言1 函数1.1 概述1.2 函数定义1.3 函数调用1.4 值传递1.5 函数常见样式1.6 函数声明1.7 函数分文件编写1.8 函数默认参数1.9 函数占位参数1.9 函数重载1.9.1 函数重载概述1.9.2 函数重载注意事项 2 指针2.1 指针基本概念2.2 指针变量定义和使用…...

虚拟人与娱乐传媒融合,推动综艺新模式
经过多年的更新迭代和市场的推动,虚拟人技术正在逐渐迈向成熟:3D虚拟形象的制作变得越来越精致且真实,并且出现了越来越多功能丰富使用便捷的动捕设备。因此,包括综艺影视在内的诸多领域,开始尝试将虚拟人技术融入行业…...

Linux_红帽8学习笔记分享_5
Linux_红帽8学习笔记分享_5 文章目录 Linux_红帽8学习笔记分享_51. UMASK反掩码1.1如何查看反掩码umask1.2 UMASK反掩码的作用1.2.1对于目录来说1.2.2对于文件来说 1.3如何修改UMASK反掩码1.4普通用户反掩码的测试 2.whereis的使用3. SUID权限弥补(主要针对文件,所有者执行位变…...

网络编程及项目思路
计算机和计算机之间通过网络进行数据传输 常见的软件架构: C/S:客户端/服务器 画面可以做的非常精美,用户体验好需要开发客户端,也需要开发服务端用户需要下载和更新的时候太麻烦 B/S:浏览器/服务器 不需要开发客户端,只需要…...

GD(兆易创新)系列FLASH进行FPGA和ZYNQ配置固化相操作
写在前面 本文主要针对使用GD(兆易创新)系列的FLASH做启动配置片时,遇到的相关问题进行简单整理复盘,避免后人踩坑。 本人操作固化芯片型号为:ZYNQ7045、690T(复旦微替代型号V7 690T)。 7系列…...

通过一个小例子来看一下C语言指针 p、*p、p、*p、*p分别代表什么
前言 在C语言中,指针是非常重要的概念。指针是一个变量,其值为另一个变量的地址。使用指针可以直接访问内存中的数据,这使得C语言非常灵活和强大。在学习C语言时相比大家都已经知道了&和*的区别了,但是你知道*&p和&*…...

【内摹访谈】谈谈AI爆发前夜的B端设计
本文来自摹客产品设计团队(MPD)的设计专栏“内摹访谈”。专栏介绍:专栏名称来源于西方美学理论「内摹仿说」,意指审美活动与摹仿活动紧密相连,审美不只针对表象动作,其核心在于由物及我,从表观带…...

Redis—AOF持久化
一、AOF定义 保存写操作命令到日志的持久化方式,就是 Redis 里的 AOF(Append Only File) 持久化功能 定义:以日志的形式记录每个操作,记录写指令不记录读指令,只许追加⽂件不允许修改,AOF保存的是appendonly.aof⽂件…...

OpenCV实例(五)指纹识别
OpenCV实例(五)指纹识别 1.指纹识别概述1.1概述1.2原理 2.指纹识别算法2.1特征提取2.2MCC匹配方法2.3尺度不变特征变换(SIFT) 3.显示指纹的关键点4.基于SIFT的指纹识别 作者:Xiou 1.指纹识别概述 1.1概述 指纹识别&…...

第二章 法的内容与形式
目录 第一节 法的内容与形式的概念 一、法的内容与形式的含义 二、法的内容和形式的关系 第二节 法律权利与法律义务 一、权利和义务的概念 二、权利和义务的分类 三、权利与义务的联系 第三节 法的成文形式与不成文形式 一、历史上各种法的表现形式 二、成文法与不成文…...

外包干了四年,感觉废了..
先说一下自己的情况,大专生,18年通过校招进入湖南某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…...

Git如何推送当前代码到远程仓库
第一种方法 (建立在已经配置好用户变量和ssh基础上) 在本地创建git仓库 git init 绑定远程仓库,origin是给远程仓库起的别名,也可以起其他名字,但是如果用origin,git push时可以不指出名字,如果…...

第五章 工厂模式
文章目录 一、简单工厂模式1、传统方式实现披萨订购( 可以忽略)披萨父类 Pizza子类胡椒披萨 PepperPizza子类印度披萨 GreekPizza订购披萨 OrderPizza订购披萨的 客户端 PizzaStore运行结果传统的方式的优缺点,新增子类需要修改的地方牵扯太多传统方式的究极耦合 2、…...

Spring MVC 参数解析(13)
目录 简介 调用流程 1. 首先,还是需要进行到前端控制器的doDispatch方法,这是我们的调用Spring MVC的核心入口方法 2. 在doDispatch方法内部,我们调用到了HandlerAdapter.handle(*****) 方法 3. 最终,我们会来到 RequestMappi…...

探索 Qt WebEngineWidgets:从底层原理到高级应用与技巧
探索 Qt WebEngineWidgets:从底层原理到高级应用与技巧 (Exploring Qt WebEngineWidgets: From Fundamentals to Advanced Applications and Techniques 一、Qt WebEngineWidgets 模块简介及原理 (Introduction and Principles of Qt WebEngineWidgets Module)1. Qt…...

leetcode160. 相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后&…...

核心业务7:放款实现
核心业务7:放款实现 1.放款实现流程 -------------------未完成生成借款人还款计划和投资人回款计划-------------- 2.数据库表 3.前端流程 4.汇付宝流程 5.尚融宝后端流程 -------------------未完成生成借款人还款计划和投资人回款计划-------------- -------------…...

STM32F4系列芯片RTC模块介绍
RTC是“实时时钟”的缩写,它是一种芯片,在计算机等电子产品中广泛应用。RTC提供了实时时钟计时功能和存储时间的能力,即时钟模块,常用于控制和记录时间的应用场合。 RTC的工作原理 RTC主要由时钟电路、电源管理电路、晶振电路、…...