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

06会话管理

目录

本节大纲

一、简介

二、会话并发管理

1. 简介

2. 开启会话管理

3. 测试会话管理

三、会话失效处理

1. 传统 web 开发处理

2. 前后端分离开发处理

四、禁止再次登录

五、会话共享

六、实战

1. 引入依赖

2. 编写配置

3. 配置Security

4. 测试


本节大纲

  • 简介
  • 会话并发管理
  • 会话共享实战

一、简介

当浏览器调用登录接口登录成功后,服务端会和浏览器之间建立一个会话 (Session) 浏览器在每次发送请求时都会

携带一个 Sessionld,服务端则根据这个 Sessionld 来判断用户身份。

当浏览器关闭后,服务端的 Session 并不会自动销毁,需要开发者手动在服务端调用Session销毁方法,或者等

Session 过期时间到了自动销毁。

在Spring Security 中,与HttpSession相关的功能由SessionManagementFiter 和

SessionAutheaticationStrateey 接口来处理,SessionManagomentFilter 过滤器将 Session 相关操作委托

给 SessionAuthenticationStrateey 接口去完成。

二、会话并发管理

1. 简介

会话并发管理就是指在当前系统中,同一个用户可以同时创建多少个会话,如果一个设备对应一个会话,那么也

可以简单理解为同一个用户可以同时在多少台设备上进行登录。默认情况下,同一用户在多少台设备上登录并没

有限制,不过开发者可以在 Spring Security 中对此进行配置。

2. 开启会话管理

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {//...@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().rememberMe().and().csrf().disable().sessionManagement()  //开启会话管理.maximumSessions(1);  //设置会话并发数为 1}@Beanpublic HttpSessionEventPublisher httpSessionEventPublisher() {return new HttpSessionEventPublisher();}
}
  1. sessionManagement() 用来开启会话管理、maximumSessions 指定会话的并发数为 1。
  2. HttpSessionEventPublisher 提供一一个Htp SessionEvenePubishor-实例。
    Spring Security中通过一个 Map 集合来集护当前的 Http Session 记录,进而实现会话的并发管理。
    当用户登录成功时,就向集合中添加一条Http Session 记录;当会话销毁时,就从集合中移除一条 Httpsession 记录。
    HtpSesionEvenPublisher 实现了 Fttp SessionListener 接口,可以监听到 HtpSession 的创建和销毀事件,并将 Fltp Session 的创建/销毁事件发布出去,这样,当有 HttpSession 销毀时,Spring Security 就可以感知到该事件了。

3. 测试会话管理

配置完成后,启动项目。这次测试我们需要两个浏览器,如果使用了 Chrome 浏览器,可以使用 Chrome 浏览器

中的多用户方式(相当于两个浏览器)先在第一个浏览器中输入 http://localhost:8080,此时会自动跳转到登录

页面,完成登录操作,就可以访问到数据了;

接下来在第二个浏览器中也输入 http://localhost:8080,也需要登录,完成登录操作;当第二个浏览器登录成功

后,再回到第一个浏览器,刷新页面。

结果出现下图:

三、会话失效处理

1. 传统 web 开发处理

protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().....sessionManagement()  //开启会话管理.maximumSessions(1)  //允许同一个用户只允许创建一个会话.expiredUrl("/login");//会话过期处理
}

2. 前后端分离开发处理

@Override
protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated()......sessionManagement()  //开启会话管理.maximumSessions(1)  //允许同一个用户只允许创建一个会话//.expiredUrl("/login")//会话过期处理  传统 web 开发.expiredSessionStrategy(event -> {HttpServletResponse response = event.getResponse();response.setContentType("application/json;charset=UTF-8");Map<String, Object> result = new HashMap<>();result.put("status", 500);result.put("msg", "当前会话已经失效,请重新登录!");String s = new ObjectMapper().writeValueAsString(result);response.setContentType("application/json;charset=UTF-8");response.getWriter().println(s);response.flushBuffer();});//前后端分离开发处理
}

四、禁止再次登录

默认的效果是一种被 “挤下线”的效果,后面登录的用户会把前面登录的用户 “挤下线”。

还有一种是禁止后来者登录,即一旦当前用户登录成功,后来者无法再次使用相同的用户登录,直到当前用户主

动注销登录,配置如下:

@Override
protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().....sessionManagement()  //开启会话管理.maximumSessions(1)  //允许同一个用户只允许创建一个会话//.expiredUrl("/login")//会话过期处理  传统 web 开发.expiredSessionStrategy(event -> {HttpServletResponse response = event.getResponse();response.setContentType("application/json;charset=UTF-8");Map<String, Object> result = new HashMap<>();result.put("status", 500);result.put("msg", "当前会话已经失效,请重新登录!");String s = new ObjectMapper().writeValueAsString(result);response.getWriter().println(s);response.flushBuffer();})//前后端分离开发处理.maxSessionsPreventsLogin(true);//登录之后禁止再次登录
}

五、会话共享

前面所讲的会话管理都是单机上的会话管理,如果当前是集群环境,前面所讲的会话管理方案就会失效。

此时可以利用 spring-session 结合 redis 实现 session 共享。

六、实战

1. 引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId>
</dependency>

2. 编写配置

spring.redis.host=localhost
spring.redis.port=6379

3. 配置Security

package com.blr.config;import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final FindByIndexNameSessionRepository sessionRepository;@Autowiredpublic SecurityConfig(FindByIndexNameSessionRepository sessionRepository) {this.sessionRepository = sessionRepository;}@Beanpublic UserDetailsService userDetailsService() {....}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().rememberMe().and().csrf().disable().sessionManagement()  //开启会话管理.maximumSessions(1)  //允许同一个用户只允许创建一个会话*/.expiredUrl("/login")//会话过期处理  传统 web 开发.expiredSessionStrategy(event -> {HttpServletResponse response = event.getResponse();response.setContentType("application/json;charset=UTF-8");Map<String, Object> result = new HashMap<>();result.put("status", 500);result.put("msg", "当前会话已经失效,请重新登录!");String s = new ObjectMapper().writeValueAsString(result);response.getWriter().println(s);response.flushBuffer();}).sessionRegistry(sessionRegistry());//前后端分离开发处理//.maxSessionsPreventsLogin(true);//登录之后禁止再次登录*/}@Beanpublic SpringSessionBackedSessionRegistry sessionRegistry() {return new SpringSessionBackedSessionRegistry(sessionRepository);}}

4. 测试

http://www.dtcms.com/a/263908.html

相关文章:

  • 前端计算机视觉:使用 OpenCV.js 在浏览器中实现图像处理
  • 量化选股策略 聚宽
  • 如何利用Charles中文版抓包工具提升API调试与网络性能
  • 二刷 苍穹外卖day10(含bug修改)
  • 如何使用StartUML绘制类图,用例图,时序图入门
  • 转录组分析流程(二):差异分析
  • MySQL MVCC 详解
  • ChatGPT使用限额记录与插件统计
  • 杭州来未来科技 Java 实习面经
  • [C#] WPF - 自定义样式(Slider篇)
  • 【Hive SQL优化完全指南:从0.x到4.x的性能进化之路】
  • c# IO密集型与CPU密集型任务详解,以及在异步编程中的使用示例
  • [2025CVPR]DE-GANs:一种高效的生成对抗网络
  • 微分几何、旋量理论、李群李代数、黎曼度量、微分流形、SE(3)、SO(3)
  • java微服务-linux单机CPU接近100%优化
  • Jenkins × 容器技术:构建未来DevOps生态的超级引擎
  • 插入排序解析
  • C++ dll lib 以及编译链接加载的底层机制
  • 【从历史数据分析英特尔该如何摆脱困境】
  • 跨境证券交易系统合规升级白皮书:全链路微秒风控+开源替代,护航7月程序化交易新规落地
  • 手工部署与自动化部署场景模拟及参考项目
  • 数据结构与算法 第二章 线性表
  • Disruptor架构哲学
  • 【算法 day13】LeetCode 110.平衡二叉树 | 257. 二叉树的所有路径| 404.左叶子之和 |222.完全二叉树的节点个数
  • 【Python】字典get方法介绍
  • C++中的虚函数与纯虚函数
  • 【PaddleOCR】快速集成 PP-OCRv5 的 Python 实战秘籍--- PaddleOCR实例化 OCR 对象的参数介绍
  • css函数写个loading动画 | css预编译scss使用
  • YOLOv11性能评估全解析:从理论到实战的指标指南
  • GitHub已破4.5w star,从“零样本”到“少样本”TTS,5秒克隆声音,冲击传统录音棚!