弹簧反应的弹簧安全会话超时

Posted

技术标签:

【中文标题】弹簧反应的弹簧安全会话超时【英文标题】:Spring security session timeout for spring reactive 【发布时间】:2020-09-19 19:42:54 【问题描述】:

我有一个集成了 Spring Security 的反应式应用程序,它是由 spring initilizer 创建的,主要包含 thre3 个包(spring boot、spring security 和 webflux)。

我试图通过application.properties中的配置来配置会话超时:

spring.session.timeout=1m

使用mvn spring-boot:run 启动应用程序后,http://localhost:8080 可以访问它并要求我登录(默认安全设置)。我可以使用用户名user 和控制台上生成的密码登录。

根据我的配置,我预计在 1 分钟空闲时间后,当我再次刷新页面 http://localhost:8080 时,它可以要求我重新登录。但事实上它没有,直到 30 分钟后

所以我怀疑上面的配置不起作用

我是否使用了错误的配置?

repo repo 可以在这里找到:https://github.com/ZhuBicen/ReactiveSpringSecurity.git

【问题讨论】:

我测试了更多。 "server.servlet.session.timeout" 适用于 common(NonWebFlux) spring security,但不适用于 Webflux 【参考方案1】:

Spring 可能应该允许像对 servlet 一样,为您的上述情况为反应式堆栈进行自动配置。

但是,“会话”是状态,除非有一些持久性存储支持它,否则该状态不会扩展。您可以将 Spring Session 抽象与内存中的 ReactiveSessionRepository 一起使用,即使您(还)没有像 Redis 之类的后备存储。当您获得适当的支持后备存储并添加相应的依赖项时,您可以删除内存中的ReactiveSessionRepository,因为 Spring Boot 会为您自动配置您的 ReactiveSessionRepository

首先,添加spring session依赖

    <dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session-core</artifactId>
    </dependency>

其次,手动创建ReactiveSessionRepository bean。 (注意:如果您使用 Redis 而不是内存等,这可以为您自动配置。)

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.session.SessionProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.ReactiveMapSessionRepository;
import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.config.annotation.web.server.EnableSpringWebSession;

import java.util.concurrent.ConcurrentHashMap;

/**
 * This ReactiveSessionRepository isn't auto-configured so we need to create it and manually set the timeout on it.
 * Later, ReactiveRedisSessionRepository will be auto-configured so we can delete this
 */
// https://www.baeldung.com/spring-session-reactive#in-memory-configuration
@Configuration
@EnableSpringWebSession
@RequiredArgsConstructor // if lombok
@Slf4j // if lombok
public class SessionConfig 

    private final SessionProperties sessionProperties;

    @Bean
    public ReactiveSessionRepository reactiveSessionRepository() 
        ReactiveMapSessionRepository sessionRepository = new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
        int defaultMaxInactiveInterval = (int) sessionProperties.getTimeout().toSeconds();
        sessionRepository.setDefaultMaxInactiveInterval(defaultMaxInactiveInterval);
        log.info("Set in-memory session defaultMaxInactiveInterval to  seconds.", defaultMaxInactiveInterval);
        return sessionRepository;
    

第三,设置属性spring.session.timeout=3600

【讨论】:

【参考方案2】:

我终于通过实现自定义ServerAuthenticationSuccessHandler来修复它,例如:

class SuccessHandler extends RedirectServerAuthenticationSuccessHandler 

    @Override
    public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) 
        // set to -1 means the session will never expired
        // webFilterExchange.getExchange().getSession().subscribe(session->session.setMaxIdleTime(Duration.ofSeconds(-1)));
        webFilterExchange.getExchange().getSession().subscribe(session->session.setMaxIdleTime(Duration.ofMinutes(60)));
        return super.onAuthenticationSuccess(webFilterExchange, authentication);
    

SuccessHandler 也可以通过类似的方式设置:

@EnableWebFluxSecurity
public class SecurityConfig 
    @Bean
    SecurityWebFilterChain webFluxSecurityFilterChain(ServerHttpSecurity http) throws Exception 
        http.formLogin().authenticationSuccessHandler(new SuccessHandler());
        return http.build();
    

【讨论】:

【参考方案3】:

您配置的参数与您与网络浏览器的 cookie 会话无关。

该参数配置Spring Session,这是一种通过标头提供会话来处理服务、rest api 等之间会话的方法。

https://spring.io/projects/spring-session

历史上,会话 cookie 绑定到 threadlocal 中的线程,这在响应式应用程序中不起作用。因此,为了存储会话,您需要能够将会话存储在其他地方。 Redis 是您可以存储网络会话的一个示例。

这里有一个使用webflux、redis和spring session管理websession的教程。

https://www.baeldung.com/spring-session-reactive

【讨论】:

感谢您的回复,您提供的两行代码很有帮助。但是你能指出如何设置一个空闲时间跨度来控制用户应该再次输入密码的时间。目前是 30 分钟,我如何将其更改为 60 分钟? 我不知道你在说什么?空闲时间跨度?那是什么? 我的意思是设置 InMemoryCookieSession 的最大年龄时间。在定义的时间之后,可以要求用户再次进行身份验证

以上是关于弹簧反应的弹簧安全会话超时的主要内容,如果未能解决你的问题,请参考以下文章

反应式弹簧云安全(使用 Keycloak):会话到期?

使会话弹簧安全性无效

使用弹簧安全与自定义过滤器的优势?

弹簧集成dsl缓冲区

会话中的弹簧存储对象

安装时反应弹簧错误