当前位置: 首页 > news >正文

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 团队开发的&#xff0c;并且是一个自由软件&#xff0c;广泛应用于世界各地的产品和项目中【9†…...

Centos如何配置阿里云的yum仓库作为yum源?

背景 Centos在国内访问官方yum源慢&#xff0c;可以用国内的yum源&#xff0c;本文以阿里云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详细题解)

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

CSS —— display属性

用于指定一个元素在页面中的显示方式 HTML中标签元素大体被分为三种类型&#xff1a;块元素、行内元素和行内块元素 块元素 &#xff1a;block 1.独占一行 2.水平方向&#xff0c;占满它父元素的可用空间&#xff08;宽度是父级的100%&#xff09; 3.垂直方向&#xff0c;占据的…...

BTC ETF资金流入暴涨400%,市场下一步将如何发展?

近期&#xff0c;BTC现货ETF&#xff08;交易所交易基金&#xff09;市场出现了显著的资金流入&#xff0c;尤其是在9月10日&#xff0c;BTC ETF吸引了近1.17亿美元的资金流入&#xff0c;相较于前一天的3729万美元&#xff0c;暴涨了400%。这种现象引发了市场广泛关注&#xf…...

视频监控管理平台LntonAIServer视频智能分析抖动检测算法应用场景

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

初识php库管理工具composer的体验【爽】使用phpword模板功能替换里面的字符串文本

需求&#xff1a; 做了一个租赁的项目&#xff0c;里面要求签署个人授权协议&#xff0c;里面要填写姓名&#xff0c;手机号&#xff0c;身份证号&#xff0c;签署日期等参数&#xff0c;格式如下图 格式&#xff1a; 如上图&#xff0c;word中的字符串模板变量使用${varname…...

每日一问:C++ 如何实现继承、封装和多态

每日一问&#xff1a;C 如何实现继承、封装和多态 C 是一门面向对象编程语言&#xff0c;通过继承、封装和多态这三个核心特性实现了对复杂系统的高效管理和扩展。继承让代码重用性得以提升&#xff0c;封装保护数据的完整性&#xff0c;而多态通过不同的接口实现了灵活性。本文…...

STM32常用数据采集滤波算法

例如&#xff0c;STM32进行滤波处理时&#xff0c;主要目的是处理数据采集过程中可能产生的噪声和尖刺信号。这些噪声可能来自电源干扰、传感器自身的不稳定性或其他外部因素。 1.一阶互补滤波 方法&#xff1a;取a0~1,本次滤波结果&#xff08;1-a&#xff09;本次采样值a上…...

二分系列(二分查找)9/12

一、分情况讨论 1.左闭右闭:[left,right] 因为是左闭右闭&#xff0c;所以left和right都能直接取到。 #这里将>放到一起&#xff0c;当nums[mid]>target的时候&#xff0c; 要更新右边界&#xff0c;rightmid-1,这样就把一些相同的情况也切出去了 可以理解为找的第一个…...

如何通过可视化大屏,助力智慧城市的“城市微脑”建设?

在智慧城市的宏伟蓝图中&#xff0c;常常面临着一个关键挑战&#xff1a;如何确保这些理念和技术能够真正地惠及城市的每一个角落&#xff0c;每一个产业&#xff0c;以及每一位市民。问题的核心在于城市的具体应用场景&#xff0c;无论是横向的社区、园区、镇街、学校、酒店、…...

何时空仓库

某仓库现存货物 s 箱&#xff0c;每天上午出货 m 箱、下午进货 n 箱&#xff0c;若s≥m>n≥0&#xff0c;则第 k 天将会出现空仓的情况。请你帮仓库管理员编写程序&#xff0c;输入s、m 和 n&#xff0c;计算并输出 k。 输入格式 s,m,n (s≥m>n≥0) 输出格式 k 输入样例…...

美创获评CNVD年度原创漏洞发现贡献单位!

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

Spring 循环依赖原理及解决方案

一、什么是循环依赖 循环依赖指的是一个实例或多个实例存在相互依赖的关系&#xff08;类之间循环嵌套引用&#xff09;。 举例&#xff1a; Component public class AService {// A中注入了BAutowiredprivate BService bService; }Component public class BService {// B中也…...

【数据结构与算法 | 灵神题单 | 插入链表篇】力扣2807, LCR 029, 147

1. 力扣2807&#xff1a;在链表中插入最大公约数 1.1 题目&#xff1a; 你一个链表的头 head &#xff0c;每个结点包含一个整数值。 在相邻结点之间&#xff0c;请你插入一个新的结点&#xff0c;结点值为这两个相邻结点值的 最大公约数 。 请你返回插入之后的链表。 两个…...

瑞芯微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. 合并区间&#xff0c;738.单调递增的数字&#xff0c;总结 1.题目 1.1合并区间 题目链接&#xff1a;56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 视频讲解&#xff1a;贪心算法&#xff0c;合并区间有细节&#xff01;LeetCode&#x…...

深圳建站公司-如何做网站

深圳建站公司&#xff1a;如何制作一个成功的网站 在信息化快速发展的今天&#xff0c;企业和个人越来越重视网络形象&#xff0c;网站成为了展示品牌、推广产品和服务的重要平台。深圳作为科技创新和经济发展的前沿城市&#xff0c;涌现出许多专业的建站公司&#xff0c;能够为…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

机器学习的数学基础:线性模型

线性模型 线性模型的基本形式为&#xff1a; f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法&#xff0c;得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...