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

news2024/11/23 6:42:50

这是 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 {

    @Bean
    SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    UserDetailsService 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;
    }

    @Bean
    SecurityFilterChain 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();
    }

    @Bean
    HttpSessionEventPublisher sessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
}

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

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

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

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

@Service
public class LogoutService {

    @Autowired
    SessionRegistry 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.coloradmin.cn/o/1832165.html

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

相关文章

Python基础用法 之 输入 与 输出

1.输入 &#xff08;1&#xff09;什么是输入&#xff1f; 输入&#xff1a;获取键盘的输入信息。 &#xff08;2&#xff09;语法 变量 input(给使⽤者的提示信息,即告诉别⼈输入什么内容) &#xff08;3&#xff09;注意事项 代码从上到下执⾏, 当代码执⾏遇到 input 的时候…

【C++高阶】掌握C++多态:探索代码的动态之美

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;C继承 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀继承 &#x1f4d2;1. 多态的定义及实现&…

个人学习算法总结的基础crud与算法思想数据结构解释

建议都从简单的crud入手,结合生活理解了结构与操作在去进阶更难的东西,做事有规划有步骤有时间限制这样比较好进步 跳转阅读

进化生物学的数学原理 知识点总结

1、进化论与自然选择 1.1 进化论 1、进化论 过度繁殖 -> 生存竞争 -> 遗传和变异 -> 适者生存 2、用进废退学说与自然选择理论 用进废退&#xff1a;一步适应&#xff1a;变异 适应 自然选择&#xff1a;两步适应&#xff1a;变异 选择 适应 3、木村资生的中性…

Mysql开启查询日志(General Log)

1、增加配置&#xff1a; /etc/my.cnf [mysqld] general_log1 general_log_file/var/log/mysql/query.log 2、增加目录和文件&#xff0c;并且授权 可以使用以下命令修改权限&#xff1a; 创建目录&#xff1a;sudo mkdir -p /var/log/mysql 更改目录所有者&#xff1a;sudo…

[环境配置]vscode通过ssh连接autodl进行项目开发

警告&#xff1a;如果使用VSCode直接执行或开终端执行训练程序&#xff0c;请在调试完成后最后通过screen/tmux工具开守护进程&#xff0c;确保程序不受SSH连接中断影响程序执行&#xff01; 官方文档&#xff1a;请戳 AutoDL使用方法&#xff1a; 在进行操作前您需要提前安装…

【日常记录】【插件】prisma 链接MySQL数据库 简单入门

文章目录 1、新建项目&#xff0c;使用prisma链接数据库1.1、先创建一个项目1.2、初始化 npm 配置文件及下载依赖1.3、初始化TS配置文件1.4、初始化 prisma1.5、更改 prisma/schema.prisma1.6 更改.env 文件1.7 编写 prisma/schema.prisma1.8 将编写的 prisma/schema.prisma 映…

实时数仓Hologres V2.2发布,Serverless Computing降本20%

Highlight 新发布Serverless Computing&#xff0c;提升大任务稳定性&#xff0c;同时可降低20%计算成本 引擎性能优化&#xff0c;TPC-H 1TB测试相对V1.X 提升100% 实时湖仓加速架构升级&#xff0c;支持Paimon&#xff0c;直读ORC、Parquet数据性能提升5倍以上 新增实例监…

如何安全进行亚马逊、沃尔玛测评?

在亚马逊、沃尔玛、速卖通、阿里国际站等电商平台上&#xff0c;测评已成为一种高效的推广手段&#xff0c;但伴随的风险也不容忽视。这些风险主要源于平台严格的大数据风控机制&#xff0c;它涵盖了多个方面&#xff0c;以确保评价的真实性和合规性。 首先&#xff0c;硬件参数…

解决 uniapp h5 页面在私有企微iOS平台 间歇性调用uni api不成功问题(uni.previewImage为例)。

demo <template><view class"content"><image class"logo" src"/static/logo.png"></image><button click"previewImage">预览图片</button></view> </template><script> //打…

数据可视化实验一:Panda数据处理及matplotlib绘图初步

目录​​​​​​​ 2024-6-17 一、请将所有含有发明家“吴峰”的发明专利的“申请日”打印出来。并将含有“吴峰”的所有发明专利条目保存到Excel中 1.1 代码实现 1.2 运行结果 二、读取文件创建城市、人口、性别比、城镇化率DataFrame对象&#xff0c;计算指标排名&…

AI写代码,CS还有前途吗?加州大学伯克利分校:CDSS申请人数激增48%!

目录 01 CS入学人数暴涨 02 人类Coder可堪大任 03 AI还没有学会创新 04 编程与农耕不同 AI写了这么多代码&#xff0c;你还应该学习计算机科学吗&#xff1f; 新的数据显示&#xff0c;学生们仍然热衷于选修计算机科学&#xff1a;加州大学伯克利分校&#xff08;UCB&#…

AI大模型应用(1)OpenAi API快速入门

AI大模型应用(1)OpenAi API快速入门 2022 年 11 月&#xff0c;ChatGPT 成功面世&#xff0c;成为历史上用户增长最快的消费者应用。与 Google、FaceBook等公司不同&#xff0c;OpenAI 从初代模型 GPT-1 开始&#xff0c;始终贯彻只有解码器&#xff08;Decoder-only&#xff…

动力学笔记01——共振频率和共振带的数学定义

文章目录 0、背景描述1、正文2. 位移、速度、加速度的共振频率并不相同 0、背景描述 过去一年&#xff0c;我基本都在考虑塔架&#xff08;尤其是混塔&#xff09;频率仿真/模态分析的问题。关于这个问题&#xff0c;不仅有地基刚度&#xff0c;还有塔筒本身以及其他影响频率的…

散户必须知道!个股场外期权期限是什么?

今天带你了解散户必须知道&#xff01;个股场外期权期限是什么&#xff1f;场外个股期权是一种交易双方买卖未来某个时间以某个价格购买或卖出某种资产的权力&#xff0c;允许投资者以相对较小的期权费用获得名义本金&#xff0c;以获取更高的回报。 个股场外期权期限是什么&am…

【免费Web系列】大家好 ,今天是Web课程的第二二天点赞收藏关注,持续更新作品 !

这是Web第一天的课程大家可以传送过去学习 http://t.csdnimg.cn/K547r 员工管理 1. 修改员工 对于修改功能&#xff0c;分为两步实现&#xff1a; 点击 “编辑” 根据ID查询员工的信息&#xff0c;回显展示。 点击 “保存” 按钮&#xff0c;修改员工的信息 。 1.1 回显…

Docker(二)-Centos7安装Docker并配置镜像加速

系统用户为非root用户 1.安装条件 确定Centos版本是否是7及以上sudo vim /etc/redhat-release2.官网地址 https://docs.docker.com/engine/install/centos3.卸载已安装的旧版本 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-lates…

【问题记录】Ubuntu提示: “E: 软件包 gcc 没有可安装候选“

Ubuntu提示: "E: 软件包 gcc 没有可安装候选" 一&#xff0c;问题现象二&#xff0c;问题原因&解决方法 一&#xff0c;问题现象 在虚拟机Ubuntu中进行安装gcc命令时报错&#xff1a;“E: 软件包 gcc 没有可安装候选”: 二&#xff0c;问题原因&解决方法 …

关于使用命令行打开wps word文件

前言 在学习python-docx时&#xff0c;想在完成运行时使用命令行打开生成的docx文件。 总结 在经过尝试后&#xff0c;得出以下代码&#xff1a; commandrstart "C:\Users\86136\AppData\Local\Kingsoft\WPS Office\12.1.0.16929\office6\wps.exe" "./result…

【SpringBoot整合系列】SpringBoot整合kinfe4j

目录 kinfe4j与Swagger的区别 SpringBoot2.x整合kinfe4j1.添加依赖2.启动类注解3.创建Knife4J配置类4.实体类5.接口admin访问 api访问 常用注解汇总SpringBoot3.x整合Kinfe4j启动报错解决1.更换依赖2.启动类3.配置4.配置类5.参数实体类6.接口admin访问 api访问 各版本注解参照 …