SpringSecurity (七)session管理(会话管理)

一.项目搭建

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.huang</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test</name>
    <description>test</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

application.properties


spring.security.user.name=zhangsan
spring.security.user.password=123
server.port=8081

HelloController

		package com.huang.test;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class    HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}

SecurityConfig关键,过滤器配置在下文

二.配置会话管理

2.1过滤器链配置会话管理

默认情况下账户登录数量没有限制,但是有的业务需求一个账户只能登录一台设备,例如qq,那我们应该怎么做呢?

对,没错,继续配置我们的SecurityConfig里的过滤器链,securityFilterChain

  package com.huang.test.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.web.SecurityFilterChain;
import org.springframework.security.web.session.HttpSessionEventPublisher;

@Configuration
public class    SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                //SessionManagementFilter
                .sessionManagement()
                //设置会话的最大并发数,设置一个用户只可以在一台设备上登录
                //默认情况下,达到最大会话并发数之后,会挤掉上一次的登录
                .maximumSessions(1)
                //达到最大会话数的时候,是否要阻止下一个登录(自己设置登录)
                .maxSessionsPreventsLogin(true)
                .and().and()
                .csrf().disable();
        return http.build();
    }

}


2.2 配置会话管理的关键代码(加入过滤器链)

关键代码
注意最下面是两个.and()为了保证返回的值是HttpSession

.and()
//SessionManagementFilter
 .sessionManagement()
 //设置会话的最大并发数,设置一个用户只可以在一台设备上登录
.maximumSessions(1)
//达到最大会话数的时候,是否要阻止下一个登录,
 .and().and()

在这里插入图片描述

2.3 会话管理测试为什么要用两个浏览器

测试.(用两个浏览器登录,因为用一个浏览器开两个窗口会有cookie缓存,看似是一个用户登录两次,其实跟你同一个电脑登录qq,然后把qq下了,又在这个电脑上登录qq一样,而开两个浏览器登录qq就相当于两个电脑登录一个qq,这样才能看出来测试结果)

浏览器一:

在这里插入图片描述

浏览器二:
在这里插入图片描述

再次登录浏览器一:

在这里插入图片描述

如上所示,实现了会话管理

2.4 .and().and()的原因

上面注意一个关键:加两个.and()
在这里需要两个.and()保证返回的是HttpSecurity,因为前面配置完了最大session数,还可以配置session的策略,(这个策略是t掉之前的用户如qq,还是禁止登录)Spring Security默认的会话管理策略是t掉上一次的登录

在这里插入图片描述
在这里插入图片描述

2.5 默认会话管理策略和策略配置

先登录浏览器1用户,再登录浏览器二用户,刷新浏览器一,报出
在这里插入图片描述

Spring Security默认的会话管理策略是t掉上一次的登录,当然我们也可以去调整我们的策略如下图:
在这里插入图片描述

2.5.1 默认会话管理策略配置与测试

2.5.2 禁止登录会话管理策略配置与测试

securityFilterChain关键代码:

 //SessionManagementFilter
 .sessionManagement()
//设置会话的最大并发数,设置一个用户只可以在一台设备上登录
 //默认情况下,达到最大会话并发数之后,会挤掉上一次的登录
 .maximumSessions(1)
 //达到最大会话数的时候,是否要阻止下一个登录
.maxSessionsPreventsLogin(true)
 .and().and()

浏览器一:登录浏览器一

在这里插入图片描述

浏览器二:试图登录浏览器二,报出
在这里插入图片描述
登录完之后,再登录新的是没有办法并且会给出提示的,那我们想要登录后再去登录怎么办?把第一个用户注销试试,出现如下图

浏览器1注销登录
在这里插入图片描述

浏览器2登录报错
在这里插入图片描述

还是没办法继续登录,那这是为什么?

2.5.3 为什么禁止登录策略,注销了浏览器一的用户后还是没办法再第二个浏览器登录

这是为什么?

涉及到了会话管理的实现原理

在服务端,spring Security维护了一个会话注册表,所有登录上来的用户,都会注册到这个会话注册表中所谓的会话注册表,本质是一个Map集合,Map的key是当前用户对象!注意,是当前用户的对象哦,Map的value是一个集合,这个集合中保存着这个用户的所有会话。如下结构Map<User,List>(这里存储的session是包装后的session).这个value对应着这个用户的所有会话session,每次登录后就能够去Map里面拿出来这个用户的所有会话然后判断一下(set)就知道该不该登录了,当用户注销登录的时候,用户的session会被自动销毁,但是Map中的List集合中的session并不会自动移除,所以,就导致每次登录的时候都会判断为session已经登录,所以我们应当在用户注销登录的时候,将list集合中把用户对应的会话session移除掉,

具体操作步骤
如下所示:

securityConfig中加入配置–监听HttpSession的销毁操作

这个监听器的作用:

这个事件,可以监听到 HttpSession 的销毁操作,当有 HttpSession 销毁的时候,就将这个销毁的事件广播出去,Map收到通知,就会从value即list集合中把对应的会话session给移除

 /**
     * 这个事件,可以监听到 HttpSession 的销毁操作,当有 HttpSession 销毁的时候,就将这个销毁的事件广播出去
     * @return
     */
    @Bean
    HttpSessionEventPublisher sessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }

加了监听HttpSession的销毁操作的配置HttpsessionEventPublisher之后的测试:

浏览器一:
在这里插入图片描述

浏览器二:登录成功
在这里插入图片描述

三.那么如果我们要传递json我们应该怎么配置我们的SecurityConfig呢

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值