Spring security session timeout for spring reactive

泪湿孤枕 提交于 2021-02-16 22:59:37

问题


I have a Reactive Application with Spring Security integrated, it was created by spring initilizer with mainly thre3 packages(spring boot, spring security and webflux).

I was trying to configure the session timeout by following configuration in application.properties:

spring.session.timeout=1m

after starting the application with mvn spring-boot:run, It can be accessed by http://localhost:8080 and it asked me to login(by default security setting). I can use the username user and the password generated on the console to login.

Per my configuration, I expected that after 1 minutes idle time, when I refresh the page http://localhost:8080 again, it can ask me to re-login. But in fact it didn't , until 30 minutes later

So I suspect the above configuration is not working

Did I used the wrong configuration?

the reproduce repo can be found here: https://github.com/ZhuBicen/ReactiveSpringSecurity.git


回答1:


Spring should probably allow an auto-configuration for your case above for the reactive stack as it does for servlet.

However, "session" is state and that state won't scale unless there is some persistent storage backing it. You can use the Spring Session abstraction with an in-memory ReactiveSessionRepository even if you don't (yet) have a backing store like Redis or something. When you do get a proper supported backing store and add the corresponding dependencies, you can delete your in-memory ReactiveSessionRepository as spring boot will auto-configure your ReactiveSessionRepository for you.

First, add the spring session dependency

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

Second, manually create your ReactiveSessionRepository bean. (Note: this can be auto-configured for you if you're using Redis instead of in-memory, etc.)

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;
    }
}

Third, set the property spring.session.timeout=3600.




回答2:


I finally fixed it by implementing customized ServerAuthenticationSuccessHandler, eg:

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);
    }
}

The SuccessHandler can be setted by similar way:

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



回答3:


The parameter you have configured has nothing to do with the cookie session you have with the web-browser.

That parameter configures Spring Session which is a way to handle session between services, rest api's and such by providing a session through a header.

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

Session cookies are historically bound to threads in threadlocal, which doesn't work in reactive applications. So in order to store sessions, you need be able to store the sessions somewhere else. Redis is one example ofwhere you can store websessions.

Here is a tutorial of using webflux, redis and spring session to manage websessions.

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



来源:https://stackoverflow.com/questions/62133366/spring-security-session-timeout-for-spring-reactive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!