SpringSecurity(八)【会话管理】

news2024/7/6 18:01:54

八、会话管理


简介

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

8.1 会话并发管理

简介

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

  • 代码配置
package com.vinjcent.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.session.HttpSessionEventPublisher;

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .csrf()
                .disable()
                .sessionManagement()    // 开启会话管理
                .maximumSessions(1);    // 允许会话最大并发只能一个客户端
    }
    
    // 用于监听会话的创建和销毁
    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
}
  • 使用两个浏览器进行登录,观察一个登录之后,在进行另外一个登录,前者再次访问系统资源将会被提醒该用户正在被使用

在这里插入图片描述

  1. sessionManagement() 用来开启会话管理、sessionManagement() 用来指定会话的并发数
  2. HttpSessionEventPublisher 提供一个 HttpSessionEventPublisher 实例。SpringSecurity 中通过一个 Map 集合来维护当前的 HttpSession 记录,进而实现会话的并发管理。当用户登陆成功时,就向集合中添加一条 HttpSession 记录;当会话销毁时,就从集合中移除一条 HttpSession 记录。HttpSessionEventPublisher 实现了 HttpSessionListener 接口,可以监听到 HttpSession 的创建和销毁事件,并将 HttpSession 的 创建/销毁 事件发布出去,这样,当有 HttpSession 销毁时,SpringSecurity 就可以感知到该事件了

8.2 会话失效

传统 web 开发处理

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .anyRequest().authenticated()
                .and()
                ...
                .sessionManagement()    // 开启会话管理
                .maximumSessions(1)     // 允许会话最大并发只能一个客户端
                .expiredUrl("/toLogin");        // 会话过期处理
    }

前后端分离

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .and()
            .csrf()
            .disable()
            .sessionManagement()    // 开启会话管理
            .maximumSessions(1)     // 允许会话最大并发只能一个客户端
            // .expiredUrl("/toLogin");        // 传统架构的会话过期处理方案
            .expiredSessionStrategy(event -> {      // 前后端分离架构会话过期处理方案
                HttpServletResponse response = event.getResponse();
                HashMap<String, Object> result = new HashMap<>();
                result.put("status", 500);
                result.put("msg", "当前会话已经失效,请重新登录");
                String str = new ObjectMapper().writeValueAsString(result);
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().println(str);
                response.flushBuffer();
            });
}
  • 测试访问

在这里插入图片描述

8.3 禁止再次登录

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

在这里插入图片描述

  • 代码配置
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .and()
            .logout()   // 需要开启退出登录
            .and()
            .csrf()
            .disable()
            .sessionManagement()    // 开启会话管理
            .maximumSessions(1)
            // .expiredUrl("/toLogin")
            .expiredSessionStrategy(event -> {
                HttpServletResponse response = event.getResponse();
                HashMap<String, Object> result = new HashMap<>();
                result.put("status", 500);
                result.put("msg", "当前会话已经失效,请重新登录");
                String str = new ObjectMapper().writeValueAsString(result);
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().println(str);
                response.flushBuffer();
            })
            .maxSessionsPreventsLogin(true);    // 一旦登录,禁止再次登录
}

8.4 会话共享

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

  • 实战
    1. 引入依赖pom.xml
<!--redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--session-redis-->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
  1. 配置application.yml文件
# 端口号
server:
  port: 3035
  servlet:
    session:
      # 设置session过期时间
      timeout: 1
# 服务应用名称
spring:
  application:
    name: SpringSecurity10security
  # The Redis settings
  redis:
    # Redis服务器地址
    host: 127.0.0.1
    # Redis服务器连接端口
    port: 6379

# 日志处理,为了展示 mybatis 运行 sql 语句
logging:
  level:
    com:
      vinjcent:
        debug
  1. 配置 Security 适配器
  • WebSecurityConfigurerAdapter
package com.vinjcent.config.security;

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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    // 注入 session 仓库
    private final FindByIndexNameSessionRepository sessionRepository;

    @Autowired
    public WebSecurityConfiguration(FindByIndexNameSessionRepository sessionRepository) {
        this.sessionRepository = sessionRepository;
    }

    // 注册 session 同步到 redis 中
    @Bean
    public SessionRegistry sessionRegistry() {
        return new SpringSessionBackedSessionRegistry(sessionRepository);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .successForwardUrl("/test")
                .and()
                .logout()   // 需要开启退出登录
                .and()
                .csrf()
                .disable()
                .sessionManagement()    // 开启会话管理
                .maximumSessions(1)
                // .expiredUrl("/toLogin");
                .expiredSessionStrategy(event -> {
                    HttpServletResponse response = event.getResponse();
                    HashMap<String, Object> result = new HashMap<>();
                    result.put("status", 500);
                    result.put("msg", "当前会话已经失效,请重新登录");
                    String str = new ObjectMapper().writeValueAsString(result);
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().println(str);
                })
                .maxSessionsPreventsLogin(true)    // 一旦登录,禁止再次登录
                .sessionRegistry(sessionRegistry());     // 将 session 交给谁管理,前后端分离自定义过滤器需要配setSessionAuthenticationStrategy
    }
}
  1. 将 redis 作为全局 HttpSession(不开启redis作为HttpSession会使得前面的配置失效,导致出现每个服务有各自的 session 情况
package com.vinjcent.config.redis;

import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

@Configuration
@EnableRedisHttpSession // 将整个应用中使用session的数据全部交给redis处理
public class RedisSessionManager {

}
  1. 模拟分布式服务
  • 将当前的服务复制一份运行,并设置运行vm参数

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  1. 启动本地 redis-server 服务,测试两个服务进行登录操作,结果如图所示

在这里插入图片描述

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

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

相关文章

从硬件角度看服务器性能调优

bios整体配置bios系统设置Hyper Thread开启超线程&#xff0c;设置后lscpu命令Thread(s) per core 值显示为 2。超线程可以理解为CPU的虚拟化&#xff0c;一颗物理CPU并行执行两条流水线指令。确认处理器基本频率及睿频频率&#xff0c;部分处理器基础频率低&#xff0c;但是睿…

看完了你还能不懂JAVA内存模型(JMM),我输了

前言 开篇一个例子&#xff0c;我看看都有谁会&#xff1f;如果不会的&#xff0c;或者不知道原理的&#xff0c;还是老老实实看完这篇文章吧。 Slf4j(topic "c.VolatileTest") public class VolatileTest { static boolean run true; public static void main(S…

基于Java+Swing实现《扫雷》游戏

基于JavaSwing实现《扫雷》游戏一、系统介绍二、功能展示三、其他系统一、系统介绍 windows自带的游戏《扫雷》是陪伴了无数人的经典游戏&#xff0c;本程序参考《扫雷》的规则进行了简化&#xff0c;用java语言实现&#xff0c;采用了swing技术进行了界面化处理&#xff0c;设…

基于蚁群算法求解运钞车路径规划问题(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

[附源码]JAVA毕业设计桔子酒店客房管理系统(系统+LW)

[附源码]JAVA毕业设计桔子酒店客房管理系统&#xff08;系统LW&#xff09; 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目…

vue app开发调用原生方法实现权限访问授权处理(一)

vue app开发调用原生方法实现权限访问授权处理 前提&#xff1a;在写代码之前应该想清楚调用原生安卓、ios的方法&#xff0c;就应该遵循双端的方法规则&#xff0c;调用方法时应该注意&#xff0c;在这里先主要介绍一下注意事项&#xff1a; 根据App发布应用市场的要求&…

【sciter】安全应用列表控件总结

一、效果图 二、功能点 实现电脑文件拖拽进入到安全桌面,读取文件路径,生成应用。可以配置允许拖拽进入安全桌面的文件应用。点击添加图标,可以添加应用到安全桌面中。在安全桌面列表中每一个应用实现双击、失去焦点,获取焦点、右键事件在安全桌面列表中每一个应用可以实现…

[附源码]计算机毕业设计springboot疫情防控平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

HTML5期末大作业:用DIV+CSS技术设计的网页与实现(剪纸传统文化网页设计主题)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

二本土木工程管理毕业5年,零基础转型大数据开发,收割长沙深圳多个大数据offer...

点击上方 "大数据肌肉猿"关注, 星标一起成长点击下方链接&#xff0c;进入高质量学习交流群今日更新| 1052个转型案例分享-大数据交流群分享一位学习群同学的转型经历&#xff0c;他是二本土木类工程管理专业&#xff0c;17年毕业&#xff0c;毕业后在长沙工地从事了…

Java基于springboot+vue的汽车饰品销售购物商城系统 前后端分离

开发背景 随着我国科技和经济的发展&#xff0c;我国的汽车数量也越来越多&#xff0c;基本家家户户都拥有了自己的汽车&#xff0c;为了让汽车用起来更加的舒心&#xff0c;于是各类琳琅满目的汽车饰品也出现了。大多数时候人们在购买汽车饰品的时候都回到这些专卖店购买&…

C++之面向对象

目录 对象与类 类的语法&#xff1a; C中class与struct的区别&#xff1a; 通过类实例化对象的方式 具体案例 类作用域与分文件编写 创建circle.h头文件 创建源文件circle.cpp 创建all.cpp来作为程序的入口 封装 封装的意义 访问权限符 成员属性私有化 优点 具体…

Python解题 - 括号上色(递归)

题目 小艺酱又得到了一堆括号。括号是严格匹配的。现在给括号进行上色。上色有三个要求&#xff1a; 1、只有三种上色方案&#xff0c;不上色&#xff0c;上红色&#xff0c;上蓝色。 2、每对括号只有一个上色。 3、相邻的两个括号不能上相同的颜色&#xff0c;但是可以都不上色…

【Java面试指北】Exception Error Throwable 你分得清么?

读本篇文章之前&#xff0c;如果让你叙述一下 Exception Error Throwable 的区别&#xff0c;你能回答出来么&#xff1f; 你的反应是不是像下面一样呢&#xff1f; 你在写代码时会经常 try catch(Exception)在 log 中会看到 OutOfMemoryErrorThrowable 似乎不常见&#xff0c…

为什么大部分人做网赚是赚不到钱的,这才是真正的原因!

说实话&#xff0c;互联网已经发展到现在的水平&#xff0c;目前来看&#xff0c;互联网上只存在两种平台&#xff0c;一种是社交平台&#xff0c;一种是内容平台。 所有的抖音、知乎、小红书、搜索引擎、淘宝等等这些都是内容平台&#xff0c;如果你想要解决精准流量问题&…

JSP+MySQL基于SSM的高校毕业生就业管理系统

本高校毕业生就业管理系统主要包括系统用户管理模块、招聘信息管理模块、简历接收管理、投递简历管理、登录模块、和退出模块等多个模块。它帮助高校毕业生就业管理实现了信息化、网络化,通过测试,实现了系统设计目标,相比传统的管理模式,本系统合理的利用了高校毕业生就业管理…

配电网重构|基于新颖的启发式算法SOE的随机(SDNR)配电网重构(Matlab代码实现)【算例33节点、84节点、119节点、136节点、417节点】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f4dd;目前更新&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;电力系统相关知识&#xff0c;期刊论文&…

【数据集NO.3】人脸识别数据集汇总

文章目录前言一、IMDB-WIKI人脸数据集二、WiderFace人脸检测数据集三、GENKI 人脸图像数据集四、哥伦比亚大学公众人物脸部数据库五、CelebA人脸数据集六、美国国防部人脸库七、MTFL人脸识别数据集八、BioID人脸数据集九、PersonID人脸识别数据集十、CMU PIE人脸库十一、Youtub…

Linux虚拟内存

问题 什么是虚拟内存地址 &#xff1f;Linux 内核为啥要引入虚拟内存而不直接使用物理内存 &#xff1f;虚拟内存空间到底长啥样&#xff1f;内核如何管理虚拟内存&#xff1f;什么又是物理内存地址 &#xff1f;如何访问物理内存&#xff1f; 什么是虚拟内存地址 举一个生活…

Redis学习笔记(四)

事务 一个命令执行的队列&#xff0c;中间不会被打断或者干扰基本操作、 开启事务&#xff1a;multi 作用&#xff1a;设定事务的开启位置&#xff0c;执行此命令后&#xff0c;后续所有指令均加入事务中 执行事务&#xff1a;exec 作用&#xff1a;设定事务结束的位置&#xf…