Search code examples
springspring-bootspring-securitysession-cookieshazelcast

Unable to store spring session in Hazelcast


I'm developing a spring boot application with form login. I have a problem if my application works as more than one replica.

When I check where session is located, I found InMemoryWebSessionStore service. And I understood the source of the problem. I made sure that I had to store the session in a central point like redis, hazelcast.

I researched how to do this, and I read that I should use spring-session.

I faced following error:

Caused by: org.springframework.boot.autoconfigure.session.SessionRepositoryUnavailableException: No session repository could be auto-configured, check your configuration (session store type is 'hazelcast')

application.yml:

spring:
  session:
    store-type: hazelcast

First of all am I on the right way? Anyone have a better solution?

SecurityConfig.kt

@EnableWebFluxSecurity
class SecurityConfig {
    @Bean
    fun adminWebFilterChain(
        http: ServerHttpSecurity,
        userService: UserService,
        passwordEncoder: PasswordEncoder
    ): SecurityWebFilterChain {
        val userDetailsService = CustomUserDetailsService(userService, passwordEncoder)
        val manager = CustomUserAuthenticationManager(userDetailsService)
        manager.setPasswordEncoder(passwordEncoder)

        return http
            .csrf().disable()
            .authenticationManager(manager)
            .authorizeExchange()
            .pathMatchers("/login", "/logout").permitAll()
            .anyExchange().authenticated()
            .and().formLogin()
            .and().logout()
            .and().build()
    }

    @Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }
}

HazelcastHttpSessionConfig.kt

@Configuration
@EnableHazelcastHttpSession
class HazelcastHttpSessionConfig {}

Dependencies:

implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("io.micrometer:micrometer-registry-prometheus")
implementation("org.springframework.session:spring-session-core")
implementation("org.springframework.session:spring-session-hazelcast")

Am I on the right way? Do you have a better solution?

And do you have any idea about an error that I faced?


Solution

  • Here is what I have done to implement Spring Session with Hazelcast.

    HazelcastConfig.java

    @Configuration
    @EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = 3600)
    public class HazelcastConfig {
      
      @Bean
      public Config hazelCastConfig() {
        final Config config = new Config().setInstanceName("hazelcast-instance");
       
        config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
          .addMapAttributeConfig(springSessionAttributeConfig()).addMapIndexConfig(
            new MapIndexConfig(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false));
        
        return config;
      }
      
      private MapAttributeConfig springSessionAttributeConfig() {
        return new MapAttributeConfig()
            .setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
            .setExtractor(PrincipalNameExtractor.class.getName());
      }
    }
    

    In my pom.xml I have the following:

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

    I don't set the spring.session.store-type. You can tailor the configuration to your needs (adding kubernetes support, using it as a distributed query cache, etc).