spring security 会话管理

2024-08-31 19:36

本文主要是介绍spring security 会话管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、简介

    当浏览器调用登录接口登录成功后,服务端会和浏览器之间建立一个会话(Session)浏览器在每次发送请求时都会携带一个 Sessionld,服务端则根据这个 Sessionld 来判断用户身份当浏览器关闭后,服务端的 Session 并不会自动销毁,需要开发者手动在服务端调用Session销毁方法,或者等 Session 过期时间到了自动销毁。在Spring Security 中,与HttpSession相关的功能由 SessionManagemenFiter 和Session AutheaticationStrateey 接口来处理,SessionManagomentFilter 过滤器将Session 相关操作委托给SessionAuthenticationStrategy 接口去完成。

二、会话并发管理

   会话并发管理就是指在当前系统中,同一个用户可以同时创建多少个会话,如果一合设备对应一个会话,那么也可以简单理解为同一个用户可以同时在多少台设备上进行登录。默认情况下,同一用户在多少台设备上登录并没有限制,不过开发者可以在 Spring Security 中对此进行配置。

2.1 开启会话管理

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 自定义数据源,从内存中,后期自己写一个mybatis 从数据库查询* @throws Exception{scrypt}*/@Beanpublic UserDetailsService userDetailsService() {InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();userDetailsManager.createUser(User.withUsername("admin").password("{noop}12345").authorities("admin").build());return userDetailsManager;}/***  自定义authenticationManager 管理器,将自定义的数据源加到其中* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin()// 表单登录.loginProcessingUrl("/doLogin").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 就可以感知到该事件了。

2.2 测试会话管理

     配置完成后,启动项目。这次测试我们需要两个浏览器,如果使用了 Chrome 浏览器,可以使用 Chrome浏览器中的多用户方式(相当于两个浏览器)先在第一个浏览器中输入 http://localhost:8081,此时会自动跳转到登录页面,完成登录操作,就可以访问到数据了;接下来在第二个浏览器中也输入 http://localhost:8081,也需要登录完成登录操作;当第二个浏览器登录成功后,再回到第一个浏览器,刷新页面。结果出现下当另外一个浏览器登录后,就把前一个会话挤掉线了;

2.3 会话失效处理(传统web)

protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin()// 表单登录.loginProcessingUrl("/doLogin").and().csrf().disable().sessionManagement()// 开启会管理.maximumSessions(1) //设置会话并发数为1.expiredUrl("/login"); // 会话过期跳转页面}

这次会话失效后,就会跳到登录页面了,就不会出现这个英文提示了;

2.4 会话失效处理(前后端分离实现)

@Override
protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin()// 表单登录.loginProcessingUrl("/doLogin").and().csrf().disable().sessionManagement()// 开启会管理.maximumSessions(1) //设置会话并发数为1//.expiredUrl("/login"); // 会话过期跳转页面.expiredSessionStrategy(ses -> {HttpServletResponse response = ses.getResponse();Map<String,String> resMap = new HashMap<>();resMap.put("code","5001");resMap.put("msg","你的账号已经挤下线了,请重新登录!");String resStr = new ObjectMapper().writeValueAsString(resMap);response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);response.getWriter().println(resStr);});}

2.5 禁止再此登录

    默认的效果是一种被“挤下线”的效果,后面登录的用户会把前面登录的用户“挤下线。还有一种是禁止后来者登录,即一旦当前用户登录成功,后来者无法再次使用相同的用户登录,直到当前用户主动注销登录,配置如下:

@Override
protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin()// 表单登录.loginProcessingUrl("/doLogin")// 退出登录.and().logout().and().csrf().disable().sessionManagement()// 开启会管理.maximumSessions(1) //设置会话并发数为1//.expiredUrl("/login"); // 会话过期跳转页面.expiredSessionStrategy(ses -> {HttpServletResponse response = ses.getResponse();Map<String,String> resMap = new HashMap<>();resMap.put("code","5001");resMap.put("msg","你的账号已经挤下线了,请重新登录!");String resStr = new ObjectMapper().writeValueAsString(resMap);response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);response.getWriter().println(resStr);response.flushBuffer();}).maxSessionsPreventsLogin(true);// 一旦登录  禁止后来其它账号登录}


三、会话共享

    前面所讲的会话管理都是单机上的会话管理,也就是在单体架构,如果当前是集群环境,前面所讲的会话管理方案就会失效。此时可以利用 spring-session 结合 redis 实现 session 共享。

3.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>

3.2 代码配置

@Autowired
private RedisTemplate redisTemplate;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin()// 表单登录.loginProcessingUrl("/doLogin")// 退出登录.and().logout().and().csrf().disable().sessionManagement()// 开启会管理.maximumSessions(1) //设置会话并发数为1//.expiredUrl("/login"); // 会话过期跳转页面.expiredSessionStrategy(ses -> {HttpServletResponse response = ses.getResponse();Map<String,String> resMap = new HashMap<>();resMap.put("code","5001");resMap.put("msg","你的账号已经挤下线了,请重新登录!");String resStr = new ObjectMapper().writeValueAsString(resMap);response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);response.getWriter().println(resStr);response.flushBuffer();})//.maxSessionsPreventsLogin(true);// 一旦登录  禁止后来其它账号登录.sessionRegistry(sessionRegistry());// 将session 交给谁管理}// 创建session 同步到redis中方案
@Bean
public SpringSessionBackedSessionRegistry sessionRegistry() {FindByIndexNameSessionRepository indexNameSessionRepository = new RedisIndexedSessionRepository(redisTemplate);return new SpringSessionBackedSessionRegistry(indexNameSessionRepository);
}

最终查看redis结果

这篇关于spring security 会话管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1124812

相关文章

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

Java注解之超越Javadoc的元数据利器详解

《Java注解之超越Javadoc的元数据利器详解》本文将深入探讨Java注解的定义、类型、内置注解、自定义注解、保留策略、实际应用场景及最佳实践,无论是初学者还是资深开发者,都能通过本文了解如何利用... 目录什么是注解?注解的类型内置注编程解自定义注解注解的保留策略实际用例最佳实践总结在 Java 编程

gradle第三方Jar包依赖统一管理方式

《gradle第三方Jar包依赖统一管理方式》:本文主要介绍gradle第三方Jar包依赖统一管理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景实现1.顶层模块build.gradle添加依赖管理插件2.顶层模块build.gradle添加所有管理依赖包

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

基于Python打造一个智能单词管理神器

《基于Python打造一个智能单词管理神器》这篇文章主要为大家详细介绍了如何使用Python打造一个智能单词管理神器,从查询到导出的一站式解决,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 项目概述:为什么需要这个工具2. 环境搭建与快速入门2.1 环境要求2.2 首次运行配置3. 核心功能使用指

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推