SpringSecurity如何管理session

SessionManagementFilter是在用户认证成功后,执行一些session相关的工作,包括防止固定会话攻击,多点登录登自动下线等。用户通过扩展点,能自定义各种策略。下面是SessionManagementFilter的流程图,分为4个子流程:

  1. 认证通过,执行策略成功,保存SecurityContext,执行下一个Filter

  1. 认证通过,执行策略失败,执行身份认证失败策略(一般是重定向到登录页面),结束请求

  1. 认证不通过,当前有session信息,并且session已经失效,执行session失效策略,结束请求

  1. 认证不通过,没有session信息,执行下一个Filter

在SessionManagementFilter的流程里支持三个扩展点,基本都是在SessionManagementConfigurer 里配置:

  1. 认证成功后执行的策略

  1. 认证失败后执行的策略

  1. 执行session失效后执行的策略

认证成功后执行的策略

在SessionManagementConfigurer 的getSessionAuthenticationStrategy() 方法获取SessionAuthenticationStrategy ,返回的是CompositeSessionAuthenticationStrategy 对象。从名字上可以看出来,这是一个组合对象,包含一组策略,具体包含逻辑如下:

  1. 第一步,用户指定一个验证策略,或者使用默认策略

指定方式,http.sessionManagement(it -> it.sessionAuthenticationStrategy(null))

  1. 默认策略ChangeSessionIdAuthenticationStrategy ,也就是登录成功后会换一个SessionId,防止固定会话攻击。也可以通过http.sessionManagement(it -> it.sessionFixation(z -> z.migrateSession())) 配置来更换其他策略。

  1. 第二步,如果开启了最大用户回话数的限制,会额外添加2个策略

  1. ConcurrentSessionControlAuthenticationStrategy 将超过限制的session设置为过期状态

  1. RegisterSessionAuthenticationStrategy 把当前登录人信息记录到session上,默认是记录在内存里。可以通过SpringSession接入到Redis。

  1. 第三步,如果开启了CSRF验证,用户可以额外添加一个验证策略,或者使用默认CSRF策略

  1. 指定方式,http.csrf(it -> it.sessionAuthenticationStrategy(null))

  1. 默认策略CsrfAuthenticationStrategy ,重新设置一个新的CSRF token

认证失败后执行的策略

在ConcurrentSessionControlAuthenticationStrategy 策略时,如果用户登录的session数量超过了限制,并且设置要抛出异常(http.sessionManagement(it -> it.sessionConcurrency(sc -> sc.maxSessionsPreventsLogin(true)))),那么就会抛出SessionAuthenticationException ,从而触发认证失败策略的执行。

默认用的是SimpleUrlAuthenticationFailureHandler ,会重定向到指定页面。

执行session失效后执行的策略

这里也是配合ConcurrentSessionControlAuthenticationStrategy 策略,用户登录的session数量超过了限制时,当前session被设置了失效后,要执行的操作。默认没有执行策略,设置方法如下:

  1. 直接设置invalidSessionStrategy,http.sessionManagement(it -> it.invalidSessionStrategy(null)

  1. 设置invalidSessionUrl就会创建SimpleRedirectInvalidSessionStrategy,http.sessionManagement(it -> it.invalidSessionUrl("xx")

分布式环境下,控制用户登录session数量

关于ConcurrentSessionControlAuthenticationStrategy策略,默认情况,session是维护在内存里,所以在分布式部署模式下,就没法拿到全局的登录数。这就要调整session保存方式,我们要实现自己的SessionRegistry 。

SpringSecurity预留了扩展类SpringSessionBackedSessionRegistry ,配合SpringSession可以很方便将session存入DB、Redis等。以存入Redis为例,只需要添加几个配置:

  1. 引入spring-session-data-redis和spring-boot-starter-data-redis

<!-- 对接spring session -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
 
<!-- 自动配置redis客户端 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 开启@EnableRedisIndexedHttpSession 注解

@EnableRedisIndexedHttpSession
@AutoConfiguration
public class AutoConfiguration {
}
  1. 使用SpringSessionBackedSessionRegistry 替代默认实现,并设置maximumSessions最大并发数

@Configuration
public class SecurityConfiguration {
    @Autowired
    FindByIndexNameSessionRepository sessionRepository;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
	    .sessionManagement(it -> it.sessionConcurrency(sc -> sc
                .sessionRegistry(new SpringSessionBackedSessionRegistry<>(sessionRepository))
                .expiredSessionStrategy(event -> {
                    log.info("expiredSessionStrategy {}", event.getSessionInformation());
                    ResponseHelper.commitHttpResponse("您已经退出,多设备登录", HttpStatus.FORBIDDEN.value(), event.getResponse());
                })
                .maximumSessions(1)))
	// 略...
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李昂的数字之旅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值