Spring Security 快速开始
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
一、认证
1、从数据中读数据完成认证
@Service
public class MyUserDetailsService implements UserDetailsService {@Overridepublic UserDetails loadUserByUsername(String username) throws AuthenticationException {MyUser myUser;// 这里模拟从数据库中获取用户信息if (username.equals("admin")) {myUser = new MyUser("admin", new BCryptPasswordEncoder().encode("123456"), new ArrayList<>(Arrays.asList("p1", "p2")));return myUser;} else {throw new UsernameNotFoundException("用户不存在");}}
}
集成User可以补充一些自己的数据,修改构造方法(或者直接使用User)
public class MyUser extends User {private int sex;private int age;private String address;public MyUser(String username, String password, List<String> authorities) {super(username, password, authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));}public int getSex() {return sex;}public void setSex(int sex) {this.sex = sex;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}
}
相关配置
@Configuration
public class MySecurityConfigurer extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}
2、实现同时多种认证方式
在1的基础上添加相关配置
/*** 手机验证码认证信息,在UsernamePasswordAuthenticationToken的基础上添加属性 手机号、验证码*/
public class MobilecodeAuthenticationToken extends AbstractAuthenticationToken {private static final long serialVersionUID = 530L;private Object principal;private Object credentials;private String phone;private String mobileCode;public MobilecodeAuthenticationToken(String phone, String mobileCode) {super(null);this.phone = phone;this.mobileCode = mobileCode;this.setAuthenticated(false);}public MobilecodeAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {super(authorities);this.principal = principal;this.credentials = credentials;super.setAuthenticated(true);}public Object getCredentials() {return this.credentials;}public Object getPrincipal() {return this.principal;}public String getPhone() {return phone;}public String getMobileCode() {return mobileCode;}public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {if (isAuthenticated) {throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");} else {super.setAuthenticated(false);}}public void eraseCredentials() {super.eraseCredentials();this.credentials = null;}
}
public class MobilecodeAuthenticationProvider implements AuthenticationProvider {private UserDetailsService userDetailsService;@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {MobilecodeAuthenticationToken mobilecodeAuthenticationToken = (MobilecodeAuthenticationToken) authentication;String phone = mobilecodeAuthenticationToken.getPhone();String mobileCode = mobilecodeAuthenticationToken.getMobileCode();System.out.println("登陆手机号:" + phone);System.out.println("手机验证码:" + mobileCode);// 模拟从redis中读取手机号对应的验证码及其用户名Map<String,String> dataFromRedis = new HashMap<>();dataFromRedis.put("code", "6789");dataFromRedis.put("username", "admin");// 判断验证码是否一致if (!mobileCode.equals(dataFromRedis.get("code"))) {throw new BadCredentialsException("验证码错误");}// 如果验证码一致,从数据库中读取该手机号对应的用户信息MyUser loadedUser = (MyUser) userDetailsService.loadUserByUsername((String)dataFromRedis.get("username"));if (loadedUser == null) {throw new UsernameNotFoundException("用户不存在");} else {MobilecodeAuthenticationToken result = new MobilecodeAuthenticationToken(loadedUser, null, loadedUser.getAuthorities());return result;}}@Overridepublic boolean supports(Class<?> aClass) {return MobilecodeAuthenticationToken.class.isAssignableFrom(aClass);}public void setUserDetailsService(UserDetailsService userDetailsService) {this.userDetailsService = userDetailsService;}
}
修改配置文件
@Configuration
public class MySecurityConfigurer extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService myUserDetailsService;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic MobilecodeAuthenticationProvider mobilecodeAuthenticationProvider() {MobilecodeAuthenticationProvider mobilecodeAuthenticationProvider = new MobilecodeAuthenticationProvider();mobilecodeAuthenticationProvider.setUserDetailsService(myUserDetailsService);return mobilecodeAuthenticationProvider;}@Beanpublic DaoAuthenticationProvider daoAuthenticationProvider() {DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());daoAuthenticationProvider.setUserDetailsService(myUserDetailsService);return daoAuthenticationProvider;}/*** 定义认证管理器AuthenticationManager* @return*/@Beanpublic AuthenticationManager authenticationManager() {List<AuthenticationProvider> authenticationProviders = new ArrayList<>();authenticationProviders.add(mobilecodeAuthenticationProvider());authenticationProviders.add(daoAuthenticationProvider());ProviderManager authenticationManager = new ProviderManager(authenticationProviders);
// authenticationManager.setEraseCredentialsAfterAuthentication(false);return authenticationManager;}@Overridepublic void configure(HttpSecurity http) throws Exception {http// 关闭csrf.csrf().disable()// 权限配置,登录相关的请求放行,其余需要认证.authorizeRequests().antMatchers("/login/*").permitAll().anyRequest().authenticated();}
}
发送登录请求
@RestController
@RequestMapping("/login")
public class TestController {@GetMapping("/hello")public String hello(){return "Hello Spring security";}@Autowiredprivate AuthenticationManager authenticationManager;/*** 用户名密码登录* @param username* @param password* @return*/@GetMapping("/usernamePwd")public Result usernamePwd(String username, String password) {UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);Authentication authenticate = null;try {authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);} catch (Exception e) {e.printStackTrace();return Result.error("登陆失败");}String token = UUID.randomUUID().toString().replace("-", "");return Result.ok(token);}/*** 手机验证码登录* @param phone* @param mobileCode* @return*/@GetMapping("/mobileCode")public Result mobileCode(String phone, String mobileCode) {MobilecodeAuthenticationToken mobilecodeAuthenticationToken = new MobilecodeAuthenticationToken(phone, mobileCode);Authentication authenticate = null;try {authenticate = authenticationManager.authenticate(mobilecodeAuthenticationToken);} catch (Exception e) {e.printStackTrace();return Result.error("验证码错误");}String token = UUID.randomUUID().toString().replace("-", "");return Result.ok(token);}
}
3、用token 校验过滤
认证成功后通常会返回一个token令牌(如jwt等)
,后续我们将token放到请求头中进行请求,后端校验该token,校验成功后再访问相应的接口
@Component
@WebFilter
public class TokenAuthenticationFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {String token = httpServletRequest.getHeader("token");// 如果没有token,跳过该过滤器if (!StringUtils.isEmpty(token)) {// 模拟redis中的数据Map map = new HashMap();map.put("test_token1", new MyUser("admin", new BCryptPasswordEncoder().encode("123456"), new ArrayList<>(Arrays.asList("p1", "p2"))));map.put("test_token2", new MyUser("root", new BCryptPasswordEncoder().encode("123456"), new ArrayList<>(Arrays.asList("p1", "p2"))));// 这里模拟从redis获取token对应的用户信息MyUser myUser = (MyUser)map.get(token);if (myUser != null) {UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(myUser, null, myUser.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authRequest);} else {throw new PreAuthenticatedCredentialsNotFoundException("token不存在");}}filterChain.doFilter(httpServletRequest, httpServletResponse);}
}
修改配置 MySecurityConfigurer
@Overridepublic void configure(HttpSecurity http) throws Exception {http// 关闭csrf.csrf().disable()// 权限配置,登录相关的请求放行,其余需要认证.authorizeRequests().antMatchers("/login/*").permitAll().anyRequest().authenticated().and()// 添加token认证过滤器.addFilterAfter(tokenAuthenticationFilter, LogoutFilter.class)// 不使用session会话管理.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);}
二、认证
1、基于方法的授权
当我们想要开启
spring
方法级安全时,只需要在任何@Configuration
实例上使用@EnableGlobalMethodSecurity
注解就能达到此目的。同时这个注解为我们提供了prePostEnabled
、securedEnabled
和jsr250Enabled
三种不同的机制来实现同一种功能。
@GetMapping("/hello")@PreAuthorize("hasAuthority('cece2')")public String hello(){return "Hello Spring security";}
也可以
@PreAuthorize("@el.verify('cece2')") 然后往容器中添加el 实例,然后使用自定义的方法验证权限
2、基于Request的授权
http.authorizeRequests(authorize -> authorize// 添加授权配置.requestMatchers("/user/list").hasAnyAuthority("USER_LIST").requestMatchers("/user/add").hasAnyAuthority("USER_ADD")// 对所有请求开启授权保护.anyRequest()// 已认证的请求会被自动授权.authenticated())
三、相关配置
Security 常用配置-CSDN博客
四:参考
Spring Security入门教程
Spring Security 实现多种认证方式
相关文章:
Spring Security 快速开始
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency> 一、认证 1、从数据中读数据完成认证 Service public class MyUserDetailsService implements UserDeta…...
Lua5.3 参考手册
《Lua 5.3 参考手册》是对 Lua 5.3 版本语言的官方定义。这份手册详细描述了 Lua 语言的语法、语义以及标准库和 C API。它是由巴西里约热内卢 Pontifical Catholic 大学的 PUC-Rio 团队开发的,并且是一个自由软件,广泛应用于世界各地的产品和项目中【9†…...

Centos如何配置阿里云的yum仓库作为yum源?
背景 Centos在国内访问官方yum源慢,可以用国内的yum源,本文以阿里云yum源为例说明。 快速命令 sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.a…...

力扣139-单词拆分(Java详细题解)
题目链接:139. 单词拆分 - 力扣(LeetCode) 前情提要: 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 最近刚学完背包,所以现在的题解都是以背包问题为基础再来写的。 如果大家不懂背包问题的话&#…...

CSS —— display属性
用于指定一个元素在页面中的显示方式 HTML中标签元素大体被分为三种类型:块元素、行内元素和行内块元素 块元素 :block 1.独占一行 2.水平方向,占满它父元素的可用空间(宽度是父级的100%) 3.垂直方向,占据的…...

BTC ETF资金流入暴涨400%,市场下一步将如何发展?
近期,BTC现货ETF(交易所交易基金)市场出现了显著的资金流入,尤其是在9月10日,BTC ETF吸引了近1.17亿美元的资金流入,相较于前一天的3729万美元,暴涨了400%。这种现象引发了市场广泛关注…...

视频监控管理平台LntonAIServer视频智能分析抖动检测算法应用场景
在视频监控系统中,视频画面的稳定性对于确保监控效果至关重要。抖动现象是指视频画面中存在不稳定或频繁晃动的情况,这可能会影响视频的清晰度和可读性。LntonAIServer通过引入抖动检测功能,帮助用户及时发现并解决视频流中的抖动问题&#x…...

初识php库管理工具composer的体验【爽】使用phpword模板功能替换里面的字符串文本
需求: 做了一个租赁的项目,里面要求签署个人授权协议,里面要填写姓名,手机号,身份证号,签署日期等参数,格式如下图 格式: 如上图,word中的字符串模板变量使用${varname…...
每日一问:C++ 如何实现继承、封装和多态
每日一问:C 如何实现继承、封装和多态 C 是一门面向对象编程语言,通过继承、封装和多态这三个核心特性实现了对复杂系统的高效管理和扩展。继承让代码重用性得以提升,封装保护数据的完整性,而多态通过不同的接口实现了灵活性。本文…...

STM32常用数据采集滤波算法
例如,STM32进行滤波处理时,主要目的是处理数据采集过程中可能产生的噪声和尖刺信号。这些噪声可能来自电源干扰、传感器自身的不稳定性或其他外部因素。 1.一阶互补滤波 方法:取a0~1,本次滤波结果(1-a)本次采样值a上…...
二分系列(二分查找)9/12
一、分情况讨论 1.左闭右闭:[left,right] 因为是左闭右闭,所以left和right都能直接取到。 #这里将>放到一起,当nums[mid]>target的时候, 要更新右边界,rightmid-1,这样就把一些相同的情况也切出去了 可以理解为找的第一个…...

如何通过可视化大屏,助力智慧城市的“城市微脑”建设?
在智慧城市的宏伟蓝图中,常常面临着一个关键挑战:如何确保这些理念和技术能够真正地惠及城市的每一个角落,每一个产业,以及每一位市民。问题的核心在于城市的具体应用场景,无论是横向的社区、园区、镇街、学校、酒店、…...
何时空仓库
某仓库现存货物 s 箱,每天上午出货 m 箱、下午进货 n 箱,若s≥m>n≥0,则第 k 天将会出现空仓的情况。请你帮仓库管理员编写程序,输入s、m 和 n,计算并输出 k。 输入格式 s,m,n (s≥m>n≥0) 输出格式 k 输入样例…...

美创获评CNVD年度原创漏洞发现贡献单位!
9月10日,第21届中国网络安全年会暨网络安全协同治理分论坛在广州成功举办。会上,美创科技首次获评“CNVD年度原创漏洞发现贡献单位”。 美创科技依托第59号安全实验室,专注数据安全技术和攻防研究。凭借深厚的技术积累与优势,被遴…...

Spring 循环依赖原理及解决方案
一、什么是循环依赖 循环依赖指的是一个实例或多个实例存在相互依赖的关系(类之间循环嵌套引用)。 举例: Component public class AService {// A中注入了BAutowiredprivate BService bService; }Component public class BService {// B中也…...

【数据结构与算法 | 灵神题单 | 插入链表篇】力扣2807, LCR 029, 147
1. 力扣2807:在链表中插入最大公约数 1.1 题目: 你一个链表的头 head ,每个结点包含一个整数值。 在相邻结点之间,请你插入一个新的结点,结点值为这两个相邻结点值的 最大公约数 。 请你返回插入之后的链表。 两个…...

瑞芯微rv1126 Linux 系统,修改系统时区,包有效方法
在 Linux 系统中,修改时区的步骤通常包括创建符号链接到正确的时区文件,并确保相关的配置文件已正确更新。然而,某些系统可能有额外的步骤或需要修改其他配置文件来使更改生效。以下是一些步骤。 1. 创建符号链接 ln -sf /usr/share/zoneinfo/Asia/Hong_Kong /etc/localti…...
系统架构设计师:数据库设计
简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 系统架构设计师:数据库设计前言数据库基础概念数据模型三要素数据库的三级模型和两级…...

代码随想录刷题day31丨56. 合并区间,738.单调递增的数字,总结
代码随想录刷题day31丨56. 合并区间,738.单调递增的数字,总结 1.题目 1.1合并区间 题目链接:56. 合并区间 - 力扣(LeetCode) 视频讲解:贪心算法,合并区间有细节!LeetCode&#x…...

深圳建站公司-如何做网站
深圳建站公司:如何制作一个成功的网站 在信息化快速发展的今天,企业和个人越来越重视网络形象,网站成为了展示品牌、推广产品和服务的重要平台。深圳作为科技创新和经济发展的前沿城市,涌现出许多专业的建站公司,能够为…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...