SpringSecurity(一)——认证实现
一、初步理解
SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。
当前系统中SpringSecurity过滤器链中有哪些过滤器及它们的顺序。

核心过滤器:
- (认证)UsernamePasswordAuthenticationFilter:负责处理我们在登陆页面填写了用户名密码后的登陆请求
- ExceptionTranslationFilter:处理过滤器链中抛出的任何AccessDeniedException和 AuthenticationException
- (授权)FilterSecurityInterceptor:负责权限校验的过滤器
二、Token(Jwt)登录校验流程

三、具体认证授权细节
下图是UsernamePasswordAuthenticationFilter处理用户名、密码,然后将用户名、密码、权限信息封装到Authentication对象中,再放到SecurityContextHolder中。

Authentication接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。
AuthenticationManager接口:定义了认证Authentication的方法
UserDetailsService接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的 方法。
UserDetails接口:提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装 成UserDetails对象返回。然后将这些信息封装到Authentication对象中。
认证
- 当用户登录时,前端将用户输入的用户名、密码信息传输到后台,后台用一个类对象将其封装起来,通常使用的是UsernamePasswordAuthenticationToken这个类。
- 程序负责验证这个类对象。验证方法是调用Service根据username从数据库中取用户信息到实体类的实例中,比较两者的密码,如果密码正确就成功登陆,同时把包含着用户的用户名、密码、所具有的权限等信息(用户id、昵称、是否管理员)的类对象放到SecurityContextHolder(安全上下文容器,类似Session)中去。
- 用户访问一个资源的时候,首先判断是否是受限资源。如果是的话还要判断当前是否未登录,没有的话就跳到登录页面。
- 如果用户已经登录,访问一个受限资源的时候,程序要根据url去数据库中取出该资源所对应的所有可以访问的角色,然后拿着当前用户的所有角色一一对比,判断用户是否可以访问(这里就是和权限相关)。
授权
- 在SpringSecurity中,会使用默认的FilterSecurityInterceptor来进行权限校验。在FilterSecurityInterceptor中会从SecurityContextHolder获取其中的Authentication,然后获取其中的权限信息。当前用户是否拥有访问当前资源所需的权限。
- 所以我们在项目中只需要把当前登录用户的权限信息也存入Authentication。然后设置我们的资源所需要的权限即可。
自定义登录认证接口:①调用ProviderManager的方法进行认证;②如果认证通过生成jwt;③把用户信息存入redis中
自定义权限信息查询:在UserDetailsService这个实现类中去查询数据库
四、自定义权限查询
修改UsernamePasswordAuthenticationFilter上图最右边的授权部分。
1.自定义登陆接口
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@PostMapping("/login")public R login(@RequestBody User user) {String jwt = userService.login(user);if (StringUtils.hasLength(jwt)) {return R.ok().message("登陆成功").data("token", jwt);}return R.error().message("登陆失败");}
}
2.配置数据库校验登录用户
从之前的分析我们可以知道,我们可以自定义一个UserDetailsService,让SpringSecurity使用我们的 UserDetailsService。我们自己的UserDetailsService可以从数据库中查询用户名和密码。
创建一个类实现UserDetailsService接口,重写loadUserByUsername方法
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//查询用户信息QueryWrapper<User> queryWrapper=new QueryWrapper<>();queryWrapper.eq("user_name",username);User user = userMapper.selectOne(queryWrapper);//如果没有查询到用户,就抛出异常if(Objects.isNull(user)){throw new RuntimeException("用户名或密码错误");}//TODO 查询用户对应的权限信息细节见SpringSecurity(二)——授权实现//如果有,把数据封装成UserDetails对象返回return new LoginUser(user);}
}
五、Jwt认证过滤器(自定义过滤器)
(1)在接口中我们通过AuthenticationManager的authenticate方法来进行用户认证,所以需要在 SecurityConfig中配置把AuthenticationManager注入容器。
@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig{/*** 登录时需要调用AuthenticationManager.authenticate执行一次校验*/@Beanpublic AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {return config.getAuthenticationManager();}
}
(2)登录的业务逻辑层实现类
第一次登录,生成jwt存入redis
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Overridepublic String login(User user) {//1.封装Authentication对象 ,密码校验,自动完成UsernamePasswordAuthenticationToken authentication =new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());//2.进行校验Authentication authenticate = authenticationManager.authenticate(authentication);//3.如果authenticate为空if (Objects.isNull(authenticate)) {throw new RuntimeException("登录失败"); //TODO 登录失败}//4.得到用户信息LoginUser loginUser = (LoginUser) authenticate.getPrincipal();//生成jwt,使用fastjson的方法,把对象转成字符串String loginUserString = JSON.toJSONString(loginUser);//调用JWT工具类,生成jwt令牌String jwt = JwtUtils.createJWT(loginUserString, null);//5.把生成的jwt存到redisString tokenKey = "token_" + jwt;stringRedisTemplate.opsForValue().set(tokenKey, jwt, JwtUtils.JWT_TTL / 1000);Map<String, Object> map = new HashMap<>();map.put("token", jwt);map.put("username", loginUser.getUsername());return jwt;}
}
(3)jwt认证校验过滤器
我们需要自定义一个过滤器,这个过滤器会去获取请求头中的token,对token进行解析取出其中的 userid。 使用userid去redis中获取对应的LoginUser对象。
然后封装Authentication对象存入SecurityContextHolder
/*** token验证过滤器 //每一个servlet请求,只会执行一次*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate LoginFailureHandler loginFailureHandler;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain)throws ServletException, IOException {try {//1.获取当前请求的url地址String url = request.getRequestURI();//如果当前请求不是登录请求,则需要进行token验证if (!url.equals("/user/login")) {//2.验证tokenthis.validateToken(request);}} catch (AuthenticationException e) {System.out.println(e);loginFailureHandler.onAuthenticationFailure(request, response, e);}//3.登录请求不需要验证tokendoFilter(request, response, filterChain);}/*** 验证token*/private void validateToken(HttpServletRequest request) throws AuthenticationException {//1.获取tokenString token = request.getHeader("Authorization");//如果请求头部没有获取到token,则从请求的参数中进行获取if (ObjectUtils.isEmpty(token)) {token = request.getParameter("Authorization");}if (ObjectUtils.isEmpty(token)) {throw new CustomerAuthenticationException("token不存在");}//2.redis进行校验String redisStr = stringRedisTemplate.opsForValue().get("token_" + token);if(ObjectUtils.isEmpty(redisStr)) {throw new CustomerAuthenticationException("token已过期");}//3.解析tokenClaims claims = null;try {claims = JwtUtils.parseJWT(token);} catch (Exception e) {throw new CustomerAuthenticationException("token解析失败");}//4.获取到用户信息String loginUserString = claims.getSubject();//把字符串转成loginUser对象LoginUser loginUser = JSON.parseObject(loginUserString, LoginUser.class);//创建身份验证对象UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());//5.设置到Spring Security上下文SecurityContextHolder.getContext().setAuthentication(authenticationToken);}
}
(4)把jwt过滤器注册到springsecurity过滤器链中
放在UsernamePasswordAuthenticationFilter前面
@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig{//自定义jwt校验过滤器@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {//配置关闭csrf机制http.csrf(csrf -> csrf.disable());//登陆失败处理器http.formLogin(configurer -> {configurer.failureHandler(loginFailureHandler);});http.sessionManagement(configurer ->// STATELESS(无状态): 表示应用程序是无状态的,不会创建会话。configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));//请求拦截方式http.authorizeHttpRequests(auth -> auth.requestMatchers("/user/login").permitAll().anyRequest().authenticated());//!!!!!注册jwt过滤器!!!!!!!http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);//异常处理器http.exceptionHandling(configurer -> {configurer.accessDeniedHandler(customerAccessDeniedHandler);configurer.authenticationEntryPoint(anonymousAuthenticationHandler);});return http.build(); //允许跨域}/*** 登录时需要调用AuthenticationManager.authenticate执行一次校验*/@Beanpublic AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {return config.getAuthenticationManager();}
}相关文章:
SpringSecurity(一)——认证实现
一、初步理解 SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。 当前系统中SpringSecurity过滤器链中有哪些过滤器及它们的顺序。 核心过滤器: (认证)UsernamePasswordAuthenticationFilter:负责处理…...
VMWare NAT 模式下 虚拟机上不了网原因排查
vmware 按照了Linux之后 无法上网,搞定后,记录一些信息。 window有两个虚拟网卡 VMnet1 对应的是 Host-Only(仅主机模式) VMnet8 对应的是 NAT(网络地址转换模式) 在NAT模式中,需要设置NAT和D…...
R语言手工实现主成分分析 PCA | 奇异值分解(svd) 与PCA | PCA的疑问和解答
几个问题: pca可以用相关系数矩阵做吗?效果比协方差矩阵比怎么样?pca做完后变量和样本的新坐标怎么旋转获得?pca做不做scale和center对结果有影响吗?pca用因子分解和奇异值分解有啥区别?后者怎么获得变量和样本的新坐标?1. 用R全手工实现 PCA(对比 prcomp() ) 不借助包…...
第三届OpenHarmony技术大会在上海成功举办
10月12日,以“技术引领筑生态,万物智联创未来”为主题的第三届OpenHarmony技术大会(以下简称“大会”)在上海成功举办。本次大会由OpenAtom OpenHarmony(以下简称“OpenHarmony”)项目群技术指导委员会&…...
数字化:IT部门主导还是业务部门主导?
在这个瞬息万变的数字化时代,企业如同在大海中航行的小船,面对波涛汹涌的市场竞争,数字化转型已成为生存的必经之路。然而,在这条充满挑战的航线上,常常会出现一个让人纠结的问题:数字化转型究竟应该由IT部…...
MySQL表的基本查询下/分组聚合统计
1,update 对查询到的结果进行列值更新,可以和older by,where,limit合并使用,为了方便讲解,将会以题目练习的方式进行说明: 1,将孙悟空同学的数学成绩变更为 80 分 本道题和where联…...
条款3: 理解decltype
目录 一、decltype + 变量 二、decltype + 表达式 三、decltype 使用场景 一、decltype + 变量 🥭 所有的信息都会保留,数组和函数也不会退化 const int &&carref = std::move(ca); decltype(carref) bb; // bb推导为const int &&,不会被忽略掉co…...
TCP:过多的TIME_WAIT
过多的TIME_WAIT 线上问题紧急处理方式tcp_tw_reuse启用主要特点:源码 线上问题 线上机器出现了几万个TIME_WAIT,怎么办? 紧急处理方式 tcp_tw_reuse 启用 默认情况下tcp_tw_reuse是关闭状态,使用sysctl -w net.ipv4.tcp_tw_…...
化学元素分子量、氧化物系数计算python类
在网上找到的分子量计算类,做了少量修改,有原子量、分子量、氧化物系数的计算。 import re wt_dict{ #该原子量数据从CRC手册第95版提取。"H": 1.008,"He": 4.002602,"Li": 6.94,"Be": 9.0121831,"B": 10.…...
torch.utils.data.DataLoader参数介绍
torch.utils.data.DataLoader 是 PyTorch 用于加载数据的重要工具,特别是在深度学习模型训练中。它可以高效地处理大规模数据集,并支持多线程数据加载。以下是 DataLoader 的关键参数及其功能: 主要参数 dataset: 要加载的数据集,可以是 PyTorch 自带的 torch.utils.data.…...
echarts 入门
工作中第一次碰到echarts,当时有大哥。二进宫没办法,只能搞定它。 感觉生活就是这样,不能解决的问题总是会反复出现。通过看视频、查资料,完成了工作要求。写一篇Hello World,进行备查。 基本使用 快速上手 <!DO…...
WPF实现类似网易云音乐的菜单切换
这里是借助三方UI框架实现了,感兴趣的小伙伴可以看一下。 深色模式: 浅色模式: 这里主要使用了以下三个包: MahApps.Metro:UI库,提供菜单导航和其它控件 实现步骤:1、使用B…...
OpenCV人脸检测与识别:构建智能识别系统
在当今科技日新月异的时代,人脸识别技术以其独特的便利性和安全性,在各个领域都展现出了巨大的应用潜力。从智能手机的面部解锁,到机场的自动安检,再到商场的顾客行为分析,人脸识别技术无处不在。本文将深入探讨如何使…...
H5 Canvas 举牌小人
之前看到这种的举牌小人的图片觉得很有意思,最近有时间所以就尝试写写看。 在线链接 https://linyisonger.github.io/H5.Examples/?name./080.Canvas%20%E4%B8%BE%E7%89%8C%E5%B0%8F%E4%BA%BA.html 生成效果 实现代码 <!DOCTYPE html> <html lang"…...
rom定制系列------小米6x_澎湃os1.0.28安卓13定制固件修改 刷写过程与界面预览
💝💝💝 在接待很多定制化系统过程中。小米6x机型为很多工作室客户使用。但官方低版本固件无法适应新应用的使用。有些第三方固件却可以完美解决。此固件是客户分享的卡刷固件。需要修改为可以批量刷写的线刷固件。去除一些内置应用。需要自带…...
电脑硬件性能:HDD + SSD + CPU + GPU
文章目录 任务管理器:性能参数详解一、电脑的硬件组成二、机械硬盘和固态硬盘2.1、详细介绍:HDD SSD2.2、读写性能2.2.1、(HDD)读写性能的影响因素:寻道时间 旋转延迟 数据传输时间2.2.2、(SSDÿ…...
通过粒子系统customData传值给材质球
粒子特效使用的材质球,如果通过动画控制shader的某个参数,例如溶解阈值,所有的粒子都会按照相同的数值变化,如果需要每个粒子在自己的生命周期内按照曲线变化,则可以通过customData实现。 1.ParticleSystem中勾选Cust…...
常用分布的数学期望、方差、特征函数
文章目录 相关教程相关文献常用分布的数学期望&方差&特征函数定义事件域概率条件概率随机变量分布函数连续随机变量的概率密度函数数学期望离散随机变量连续随机变量 方差与标准差最大似然估计特征函数 不等式Chebyshev(切比雪夫)不等式 作者&am…...
ssh-配置
生成 SSH 密钥是一项重要的安全措施,用于在客户端和服务器之间建立加密连接。以下是在 Windows 和 Linux 系统上生成 SSH 密钥的详细步骤。 一、在 Linux 上生成 SSH 密钥 Linux 通常预装了 ssh-keygen 工具,可以通过以下步骤生成 SSH 密钥:…...
Python 在 JMeter 中如何使用?
要在JMeter中使用Python,需要使用JSR223 Sampler元素来执行Python脚本。使用JSR223 Sampler执行Python脚本时,需要确保已在JMeter中配置了Python解释器,并设置了正确的环境路径。 1、确保JMeter已安装Python解释器,并将解释器的路…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
