diff --git a/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSession.java b/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSession.java index af2387ee7..37a2e3d18 100644 --- a/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSession.java +++ b/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 the original author or authors. + * Copyright 2014-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.springframework.session.SessionRepository; import org.springframework.session.events.SessionCreatedEvent; import org.springframework.session.events.SessionDestroyedEvent; +import org.springframework.session.web.http.SessionRepositoryFilter; /** * Add this annotation to an {@code @Configuration} class to expose the @@ -67,6 +68,7 @@ * * * @author Rob Winch + * @author Yanming Zhou * @since 1.1 */ @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @@ -75,4 +77,11 @@ @Import(SpringHttpSessionConfiguration.class) public @interface EnableSpringHttpSession { + /** + * Returns the {@link SessionRepositoryFilter} class to be used. Defaults to + * {@link SessionRepositoryFilter}. + * @return the {@link SessionRepositoryFilter} class + */ + Class sessionRepositoryFilterClass() default SessionRepositoryFilter.class; + } diff --git a/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java b/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java index bd952987a..b1d08df02 100644 --- a/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java +++ b/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 the original author or authors. + * Copyright 2014-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.session.config.annotation.web.http; +import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; @@ -32,6 +33,9 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportAware; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.session.Session; import org.springframework.session.SessionRepository; import org.springframework.session.events.SessionCreatedEvent; @@ -86,11 +90,12 @@ * * @author Rob Winch * @author Vedran Pavic + * @author Yanming Zhou * @since 1.1 * @see EnableSpringHttpSession */ @Configuration(proxyBeanMethods = false) -public class SpringHttpSessionConfiguration implements InitializingBean, ApplicationContextAware { +public class SpringHttpSessionConfiguration implements InitializingBean, ApplicationContextAware, ImportAware { private final Log logger = LogFactory.getLog(getClass()); @@ -106,6 +111,18 @@ public class SpringHttpSessionConfiguration implements InitializingBean, Applica private List httpSessionListeners = new ArrayList<>(); + @SuppressWarnings("rawtypes") + private Class sessionRepositoryFilterClass = SessionRepositoryFilter.class; + + @Override + public void setImportMetadata(AnnotationMetadata importMetadata) { + AnnotationAttributes annotationAttributes = AnnotationAttributes + .fromMap(importMetadata.getAnnotationAttributes(EnableSpringHttpSession.class.getName())); + if (annotationAttributes != null) { + this.sessionRepositoryFilterClass = annotationAttributes.getClass("sessionRepositoryFilterClass"); + } + } + @Override public void afterPropertiesSet() { this.defaultHttpSessionIdResolver.setCookieSerializer(getCookieSerializer()); @@ -117,9 +134,20 @@ public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAda } @Bean + @SuppressWarnings({ "unchecked", "rawtypes" }) public SessionRepositoryFilter springSessionRepositoryFilter( SessionRepository sessionRepository) { - SessionRepositoryFilter sessionRepositoryFilter = new SessionRepositoryFilter<>(sessionRepository); + SessionRepositoryFilter sessionRepositoryFilter; + try { + Constructor ctor = this.sessionRepositoryFilterClass + .getDeclaredConstructor(SessionRepository.class); + ctor.setAccessible(true); + sessionRepositoryFilter = ctor.newInstance(sessionRepository); + } + catch (Exception ex) { + throw new IllegalArgumentException("Please make sure class [" + this.sessionRepositoryFilterClass + + "] has public constructor accepts SessionRepository parameter.", ex); + } sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver); return sessionRepositoryFilter; } diff --git a/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfigurationTests.java b/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfigurationTests.java index cb04e0551..5faf25850 100644 --- a/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfigurationTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.mock.web.MockServletContext; import org.springframework.session.MapSessionRepository; +import org.springframework.session.Session; import org.springframework.session.SessionRepository; import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices; import org.springframework.session.web.http.CookieHttpSessionIdResolver; @@ -50,6 +51,7 @@ * Tests for {@link SpringHttpSessionConfiguration}. * * @author Vedran Pavic + * @author Yanming Zhou */ class SpringHttpSessionConfigurationTests { @@ -130,6 +132,14 @@ void rememberMeServicesAndCustomDefaultCookieSerializerThenWarnIfRememberMeReque } } + @Test + void customizeSessionRepositoryFilter() { + registerAndRefresh(CustomSessionRepositoryFilterConfiguration.class); + + SessionRepositoryFilter sessionRepositoryFilter = this.context.getBean(SessionRepositoryFilter.class); + assertThat(sessionRepositoryFilter).isInstanceOf(MySessionRepositoryFilter.class); + } + @Configuration @EnableSpringHttpSession static class EmptyConfiguration { @@ -189,4 +199,18 @@ DefaultCookieSerializer defaultCookieSerializer() { } + @Configuration + @EnableSpringHttpSession(sessionRepositoryFilterClass = MySessionRepositoryFilter.class) + static class CustomSessionRepositoryFilterConfiguration extends BaseConfiguration { + + } + + public static class MySessionRepositoryFilter extends SessionRepositoryFilter { + + MySessionRepositoryFilter(SessionRepository sessionRepository) { + super(sessionRepository); + } + + } + }