Search code examples
springspring-bootredisspring-data-redisspring-session

FindByIndexNameSessionRepository “RedisConnectionFactory is required” configuration error


Implementing the logic of limiting active sessions for each user (number of possible sessions stored in the database, sessions in Redis), I came across the problem of configuring FindByIndexNameSessionRepository.

Due to the fact that I am injecting FindByIndexNameSessionRepository spring starts to configure the bean in the RedisHttpSessionConfiguration class, and the fields are not injected into the class via setters.

As a result, I get the error:

Caused by: java.lang.IllegalStateException: RedisConnectionFactory is required
at org.springframework.util.Assert.state(Assert.java:73) ~[spring-core-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.data.redis.core.RedisAccessor.afterPropertiesSet(RedisAccessor.java:38) ~[spring-data-redis-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.data.redis.core.RedisTemplate.afterPropertiesSet(RedisTemplate.java:127) ~[spring-data-redis-2.2.6.RELEASE.jar:2.2.6.RELEASE]
at org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration.createRedisTemplate(RedisHttpSessionConfiguration.java:291) ~[spring-session-data-redis-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration.sessionRepository(RedisHttpSessionConfiguration.java:120) ~[spring-session-data-redis-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]

Config code:

@EnableRedisHttpSession
@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
public class CustomConfiguration extends WebSecurityConfigurerAdapter {
    private final FindByIndexNameSessionRepository sessionRepository;    
    // ....

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/**")
                .authenticated()
                .and()
            .formLogin()
                .and()
            // ....
            .sessionManagement()
                .sessionAuthenticationStrategy(new CustomAuthenticationStrategy(sessionRegistry(), sessionsLimitRepository));
    }

    @Bean
    public SpringSessionBackedSessionRegistry sessionRegistry() {
        return new SpringSessionBackedSessionRegistry(sessionRepository);
    }

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(new RedisStandaloneConfiguration("server", 6379));
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
   }

}

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-core</artifactId>
    </dependency>

    <!-- .... -->
</dependencies>

If you remove\comment out the places where FindByIndexNameSessionRepository is used, then the RedisHttpSessionConfiguration setters are called by the "guts" of the spring when the springSessionRepositoryFilter bean is created.

If I understood correctly, then I accidentally broke the order of configuring the beans. In attempts to fix it, I tried @DependsOn, @Lazy and various frauds with moving bins to different classes of configs, changing the order of loading configs, and so on.

UPD: Add bean httpSessionEventPublisher and pom.xml


Solution

  • The main problem was that spring-boot had already configured most of the bins for me.

    To resolve this problem, you must remove @EnableRedisHttpSession (@EnableWebSecurity can also be deleted), beans redisConnectionFactory and httpSessionEventPublisher, and optionally you can remove the unnecessary dependency spring-session-core

    Actual config code:

    @Configuration
    @RequiredArgsConstructor
    public class CustomConfiguration extends WebSecurityConfigurerAdapter {
    
        private final FindByIndexNameSessionRepository<? extends Session> sessionRepository;
    
        // ....
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .antMatchers("/**")
                    .authenticated()
                    .and()
                .formLogin()
                    .and()
                // ....
                .sessionManagement()
                    .sessionAuthenticationStrategy(new CustomAuthenticationStrategy(sessionRegistry(), sessionsLimitRepository));
    }
    
        @Bean
        public SessionRegistry sessionRegistry() {
            return new SpringSessionBackedSessionRegistry<>(sessionRepository);
        }
    
    }
    

    Actual pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
    
        <!-- .... -->
    </dependencies>