管理员如何踢掉登录用户?

这是 Spring Security 学习小组有小伙伴提的一个问题:

感觉这个问题还有点意思,拿出来和各位小伙伴一起分享下。

一 问题分析

首先大家注意限制条件:常规 Session 方案

如果不是这几个字,这个问题根本就不是问题,如果是 JWT+Redis 这种方案,这个问题很好解决,自己随随便便几段逻辑处理就行了。问题是常规 Session 方案,也就是 Spring Security 默认的方案,Spring Security 默认情况下,登录用户信息保存在 HttpSession 中,HttpSession 不同用户又是不一样的 HttpSession,相当于你在一个 HttpSession 对象中要使另外一个 HttpSession 对象失效,这是这个小伙伴困惑的地方。

二 解决思路

Spring Security 中提供了一个会话并发管理的功能,就是可以设置同一个用户并发登录的数量,比如 javaboy 的并发登录数量为 1,那么 javaboy 就只能在一台设备上登录,在在其他设备登录就会被拒绝,或者其他设备登录会自动踢掉当前登录。

这一功能实现的原理是 Spring Security 中用了一个会话注册器 SessionRegistry 去统一管理登录用户的会话,当用户登录成功之后,讲用户信息保存在一个类型为 ConcurrentMap<Object, Set<String>> principals 的 Map 中,这里的 key 就是登录的用户对象,value 就是登录用户的 sessionId,当然如果想获取到登录用户会话更为详细的信息,还有一个类型为 Map<String, SessionInformation> sessionIds 的 Map,这个 Map 的 key 则是 sessionId。通过对这两个 Map 中的数据进行管理,就能实现对用户并发登录的控制。

相同的道理,我这里也想借鉴已有的功能,在这个功能的基础上,实现管理员踢出已登录用户,这样就会方便很多。

管理员踢出用户的时候,只需要遍历 principals 集合,根据用户名找出来这个用户登录的 sessionId,然后再根据 sessionId 去 sessionIds 里找到会话对应的 SessionInformation,然后令这些会话失效即可。

三 参考代码

首先需要我们自己提供 SessionRegistry 对象:

@Configuration
public class SecurityConfig {@BeanSessionRegistry sessionRegistry() {return new SessionRegistryImpl();}@BeanUserDetailsService us() {InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();manager.createUser(User.withUsername("zhangsan").password("{noop}123").roles("ADMIN").build());manager.createUser(User.withUsername("lisi").password("{noop}123").roles("ADMIN").build());return manager;}@BeanSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(a -> a.anyRequest().authenticated()).formLogin(Customizer.withDefaults()).csrf(c -> c.disable()).sessionManagement(s -> s.maximumSessions(Integer.MAX_VALUE).sessionRegistry(sessionRegistry()));return http.build();}@BeanHttpSessionEventPublisher sessionEventPublisher() {return new HttpSessionEventPublisher();}
}

在配置 SecurityFilterChain 的时候,传入自己配置的 sessionRegistry。

这里有一个需要注意的点,就是要开启会话并发管理,只有开启了会话并发管理,第二小节我们说的那些思路才是有效的,否则这些思路不会生效。那么怎么开启会话并发管理呢?设置会话的最大并发数即可,如果你本身并不想限制,那么这个并发数可以设置为 Integer.MAX_VALUE

这里涉及到的其他内容我就不多说了,都是课程中讲的关于会话并发管理的内容。

最后,踢出用户的逻辑如下:

@Service
public class LogoutService {@AutowiredSessionRegistry sessionRegistry;public void logout(String username) {List<Object> principals = sessionRegistry.getAllPrincipals();for (Object principal : principals) {if (principal instanceof User u) {String name = u.getUsername();if (name.equals(username)) {List<SessionInformation> allSessions = sessionRegistry.getAllSessions(u, false);for (SessionInformation session : allSessions) {session.expireNow();}}}}}
}

参数 username 就是管理员要踢出去的用户名。

sessionRegistry.getAllPrincipals(); 是获取到所有的登录用户信息,然后遍历,根据用户名找到要踢出去的用户,然后调用 sessionRegistry.getAllSessions 方法获取该用户的所有会话信息,遍历这些会话,挨个调用其 expireNow() 方法,使之失效。

这样,当用户被踢下线的感觉就像是会话并发控制的时候,被其他客户端挤下线的感觉。

当然,也可以给用户一个明确提示,类似下面这样:

.sessionManagement(s -> s.maximumSessions(Integer.MAX_VALUE).sessionRegistry(sessionRegistry()).expiredSessionStrategy(event -> {HttpServletResponse response = event.getResponse();response.setContentType("text/html;charset=utf-8");response.getWriter().print("你被管理员踢下线了");response.flushBuffer();
}));

OK,大功告成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/28734.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

确定线性稳压器的包装限制范围

工程师喜欢低压差 (LDO) 线性稳压器&#xff0c;因为它们简单、易于使用、价格低廉和低噪声。典型的线性稳压器仅需要几个外部电容器和电阻器即可完全实现 DC/DC 转换器。 通常&#xff0c;工程师根据数据表前面列出的一些规格来选择线性稳压器&#xff0c;这些规格概述了稳压…

vim 的 map+noremap

经常在 vim 的配置文件中&#xff0c;看到对于改键的设置。 他们的区别主要有两种 1 用于哪种模式。 2 是否用于递归。

基于Python的花卉识别分类系统【W9】

简介&#xff1a; 基于Python的花卉识别分类系统利用深度学习和计算机视觉技术&#xff0c;能够准确识别和分类各种花卉&#xff0c;如玫瑰、郁金香和向日葵等。这种系统不仅有助于植物学研究和园艺管理&#xff0c;还在生态保护、智能农业和市场销售等领域展现广泛应用前景。随…

【学习笔记】MySQL(Ⅱ)

MySQL(Ⅱ) 7、 进阶篇 —— 存储引擎 7.1、MySQL 体系结构 7.2、存储引擎 7.2.1 InnoDB 7.2.2 MyISAM 7.2.3 Memory 7.2.4 InnoDB、MyISAM、Memory 的比较8、 拓展篇 —— 在 Linux 上安装数据库9、进阶篇 —— 索引 …

开源项目大合集(热门)

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

java基础知识总结【markdown】

java基础知识总结【markdown】 开发工具Java数据类型浮点数使用陷阱: 2.7 和 8.1 / 3 比较 常用字符编码基本数据类型转换关键字&#xff0c;保留字**原码、反码、补码** 开发工具 editplus、notepad、Sublime Text、IDEA、Eclipse Java数据类型 浮点数使用陷阱: 2.7 和 8.1 …

小熊家政帮day22-day23 订单系统优化(订单状态机、练习分库分表、索引、订单缓存)

目录 1 状态机1.1 状态机介绍1.1.1 当前存在的问题1.1.2 使用状态机解决问题 1.2 实现订单状态机1.2.1 编写订单状态机1.2.1.1 依赖引入1.2.1.2 订单状态枚举类1.2.1.3 状态变更事件枚举类1.2.1.4 定义订单快照类1.2.1.5 定义事件变更动作类1.2.1.5 定义订单状态机类1.2.1.6 状…

【linux网络(四)】传输层协议详解(上)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; Linux网络 1. 前言2. UDP协议…

【ARM】MDK出现报错error: A\L3903U的解决方法

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决MDK出现报错error: A\L3903U这样类型的报错 2、 问题场景 电脑或者软件因为意外情况导致崩溃&#xff0c;无法正常关闭&#xff0c;强制电脑重启之后&#xff0c;打开工程去编译出现下面的报错信息&#xff08;…

WPF 深入理解二、布局

布局与控件 常用得布局属性 HorizontalAlignment:用于设置元素的水平位置VerticalAlignment: 用于设置元素的垂直位置Margin: 指定元素与容器的边距Height: 指定元素的高度Width: 指定元素的宽度WinHeight/winWidth:指定元素的最小高度和宽度MaxHeight/MaxWidth: 指定元素的最…

压缩映射定理证明

收缩映射定理&#xff08;又称Banach不动点定理&#xff09;是一个重要的结果&#xff0c;特别是在分析和应用数学中。 定理&#xff08;收缩映射定理&#xff09;&#xff1a;假设是一个从度量空间 (X,d) 到自身的函数&#xff0c;如果 是一个收缩映射&#xff0c;即存在常数 …

华为---VLAN-配置Eth-Trunk链路聚合(三)

6.3 配置Eth-Trunk链路聚合 6.3.1 原理概述 在没有使用Eth-Trunk前&#xff0c;百兆以太网的双绞线在两个互连的网络设备间的带宽仅为100Mbit/s。若想达到更高的数据传输速率&#xff0c;则需要更换传输媒介&#xff0c;使用千兆光纤或升级成为千兆以太网。这样的解决方案成本…

GenICam标准(五)

系列文章目录 GenICam标准&#xff08;一&#xff09; GenICam标准&#xff08;二&#xff09; GenICam标准&#xff08;三&#xff09; GenICam标准&#xff08;四&#xff09; GenICam标准&#xff08;五&#xff09; GenICam标准&#xff08;六&#xff09; 文章目录 系列文…

【Stable Diffusion教程】AI绘画工具SD如何安装使用?三种方法带你轻松上手!(附安装包和云端部署教程)

大家好&#xff0c;我是向阳 AI绘画专业工具Stable Diffusion在哪里用怎么安装&#xff1f;这一期给大家介绍三种使用SD的方法&#xff0c;无论你有没有专业显卡都能轻松上手SD哦&#xff5e; 一、SD本地部署秋葉安装包安装方法 如果你有进一步的需求&#xff0c;想要学习SD…

丘钛微注册陷入“停滞”IPO中止:营收净利润连年下滑,毛利率骤降

《港湾商业观察》施子夫 王璐 从2021年6月末算起&#xff0c;在冲刺创业板这条道路上&#xff0c;昆山丘钛微电子科技股份有限公司&#xff08;以下简称&#xff0c;丘钛微&#xff09;已经耗时了三年。 实际上在三年中&#xff0c;丘钛微早在2022年8月17日就首发过会&#…

52.Python-web框架-Django - 多语言编译-fuzzy错误

目录 1.起因 2.原因 3.解决方法 3.1手动移除fuzzy标记 3.2重新生成po文件&#xff0c;并检查是否还存在fuzzy标记 3.3重新编译生成mo文件 1.起因 在Django的国际化和本地化过程中&#xff0c;当你发现某些字段仅显示msgid&#xff0c;而不显示msgstr时&#xff0c;可能是…

燃气守护神:燃气管网安全运行监测解决方案

在这个智能科技日新月异的时代&#xff0c;燃气安全却时有发生&#xff0c;严重危害人们的生命财产安全&#xff0c;因此旭华智能根据相关政策要求并结合自身优势&#xff0c;打造了一套燃气管网安全运行监测解决方案&#xff0c;他犹如一位“燃气守护神”&#xff0c;悄然守护…

计算机组成原理之存储器

文章目录 存储器概述存储器的分类情况按照存储器在系统中的作用分类按存储介质分类按存取方式分类 主存储器的技术指标 存储器概述 程序的局部性原理&#xff08;构成多级存储系统的依据&#xff09;&#xff1a;在某一个时间段你频繁访问某一局部的存储器地址空间&#xff0c;…

綦江蜘蛛池四川官网下载

baidu搜索&#xff1a;如何联系八爪鱼SEO? baidu搜索&#xff1a;如何联系八爪鱼SEO? baidu搜索&#xff1a;如何联系八爪鱼SEO? CCSEO蜘蛛统计开发思路一般包括以下几个步骤: 定义需求:明确统计蜘蛛访问数据的目标和要求,例如需要获取哪些信息,统计的精度和频率等。 确定数…

重生之 SpringBoot3 入门保姆级学习(18、事件驱动开发解耦合)

重生之 SpringBoot3 入门保姆级学习&#xff08;18、事件驱动开发解耦合&#xff09; 5、SpringBoot3 核心5.1 原始开发5.2 事件驱动开发 5、SpringBoot3 核心 5.1 原始开发 LoginController package com.zhong.bootcenter.controller;import com.zhong.bootcenter.service.A…