Introduce SessionIdGenerationStrategy

Closes gh-11
This commit is contained in:
Marcus Da Coregio
2023-03-07 17:55:18 -03:00
committed by Marcus Hert Da Coregio
parent 2e1275333a
commit d547b33962
39 changed files with 1074 additions and 30 deletions

View File

@@ -62,6 +62,8 @@ import org.springframework.session.MapSession;
import org.springframework.session.PrincipalNameIndexResolver;
import org.springframework.session.SaveMode;
import org.springframework.session.Session;
import org.springframework.session.SessionIdGenerationStrategy;
import org.springframework.session.UuidSessionIdGenerationStrategy;
import org.springframework.transaction.support.TransactionOperations;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -252,6 +254,8 @@ public class JdbcIndexedSessionRepository implements
private ThreadPoolTaskScheduler taskScheduler;
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
/**
* Create a new {@link JdbcIndexedSessionRepository} instance which uses the provided
* {@link JdbcOperations} and {@link TransactionOperations} to manage sessions.
@@ -461,7 +465,7 @@ public class JdbcIndexedSessionRepository implements
@Override
public JdbcSession createSession() {
MapSession delegate = new MapSession();
MapSession delegate = new MapSession(this.sessionIdGenerationStrategy);
delegate.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
JdbcSession session = new JdbcSession(delegate, UUID.randomUUID().toString(), true);
session.flushIfRequired();
@@ -686,6 +690,16 @@ public class JdbcIndexedSessionRepository implements
TypeDescriptor.valueOf(Object.class));
}
/**
* Set the {@link SessionIdGenerationStrategy} to use to generate session ids.
* @param sessionIdGenerationStrategy the {@link SessionIdGenerationStrategy} to use
* @since 3.2
*/
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
Assert.notNull(sessionIdGenerationStrategy, "sessionIdGenerationStrategy cannot be null");
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
}
private enum DeltaValue {
ADDED, UPDATED, REMOVED
@@ -721,7 +735,7 @@ public class JdbcIndexedSessionRepository implements
*/
final class JdbcSession implements Session {
private final Session delegate;
private final MapSession delegate;
private final String primaryKey;
@@ -773,7 +787,9 @@ public class JdbcIndexedSessionRepository implements
@Override
public String changeSessionId() {
this.changed = true;
return this.delegate.changeSessionId();
String newSessionId = JdbcIndexedSessionRepository.this.sessionIdGenerationStrategy.generate();
this.delegate.setId(newSessionId);
return newSessionId;
}
@Override

View File

@@ -50,6 +50,8 @@ import org.springframework.session.IndexResolver;
import org.springframework.session.MapSession;
import org.springframework.session.SaveMode;
import org.springframework.session.Session;
import org.springframework.session.SessionIdGenerationStrategy;
import org.springframework.session.UuidSessionIdGenerationStrategy;
import org.springframework.session.config.SessionRepositoryCustomizer;
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
@@ -109,6 +111,8 @@ public class JdbcHttpSessionConfiguration implements BeanClassLoaderAware, Embed
private StringValueResolver embeddedValueResolver;
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
@Bean
public JdbcIndexedSessionRepository sessionRepository() {
JdbcTemplate jdbcTemplate = createJdbcTemplate(this.dataSource);
@@ -144,6 +148,7 @@ public class JdbcHttpSessionConfiguration implements BeanClassLoaderAware, Embed
else {
sessionRepository.setConversionService(createConversionServiceWithBeanClassLoader(this.classLoader));
}
sessionRepository.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
this.sessionRepositoryCustomizers
.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(sessionRepository));
return sessionRepository;
@@ -235,6 +240,11 @@ public class JdbcHttpSessionConfiguration implements BeanClassLoaderAware, Embed
this.sessionRepositoryCustomizers = sessionRepositoryCustomizers.orderedStream().collect(Collectors.toList());
}
@Autowired(required = false)
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2014-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.jdbc;
import org.springframework.session.SessionIdGenerationStrategy;
public class FixedSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
private final String id;
public FixedSessionIdGenerationStrategy(String id) {
this.id = id;
}
@Override
public String generate() {
return this.id;
}
}

View File

@@ -263,6 +263,12 @@ class JdbcIndexedSessionRepositoryTests {
assertThat(this.repository).extracting("taskScheduler").isNull();
}
@Test
void setSessionIdGenerationStrategyWhenNullThenException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setSessionIdGenerationStrategy(null))
.withMessage("sessionIdGenerationStrategy cannot be null");
}
@Test
void createSessionDefaultMaxInactiveInterval() {
JdbcSession session = this.repository.createSession();
@@ -769,4 +775,32 @@ class JdbcIndexedSessionRepositoryTests {
verify(lobCreator, atLeastOnce()).close();
}
@Test
void createSessionWhenSessionIdGenerationStrategyThenUses() {
this.repository.setSessionIdGenerationStrategy(() -> "test");
JdbcSession session = this.repository.createSession();
assertThat(session.getId()).isEqualTo("test");
assertThat(session.changeSessionId()).isEqualTo("test");
}
@Test
void setSessionIdGenerationStrategyWhenNullThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setSessionIdGenerationStrategy(null))
.withMessage("sessionIdGenerationStrategy cannot be null");
}
@Test
void findByIdWhenChangeSessionIdThenUsesSessionIdGenerationStrategy() {
this.repository.setSessionIdGenerationStrategy(() -> "test");
Session saved = this.repository.new JdbcSession(new MapSession(), "primaryKey", false);
saved.setAttribute("savedName", "savedValue");
given(this.jdbcOperations.query(isA(String.class), isA(PreparedStatementSetter.class),
isA(ResultSetExtractor.class))).willReturn(Collections.singletonList(saved));
JdbcSession session = this.repository.findById(saved.getId());
assertThat(session.getId()).isEqualTo(saved.getId());
assertThat(session.changeSessionId()).isEqualTo("test");
}
}

View File

@@ -43,7 +43,10 @@ import org.springframework.session.FlushMode;
import org.springframework.session.IndexResolver;
import org.springframework.session.SaveMode;
import org.springframework.session.Session;
import org.springframework.session.SessionIdGenerationStrategy;
import org.springframework.session.UuidSessionIdGenerationStrategy;
import org.springframework.session.config.SessionRepositoryCustomizer;
import org.springframework.session.jdbc.FixedSessionIdGenerationStrategy;
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
import org.springframework.session.jdbc.config.annotation.SpringSessionDataSource;
import org.springframework.test.util.ReflectionTestUtils;
@@ -318,11 +321,40 @@ class JdbcHttpSessionConfigurationTests {
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
}
@Test
void sessionIdGenerationStrategyWhenCustomBeanThenUses() {
registerAndRefresh(DataSourceConfiguration.class, CustomSessionIdGenerationStrategyConfiguration.class);
JdbcIndexedSessionRepository sessionRepository = this.context.getBean(JdbcIndexedSessionRepository.class);
SessionIdGenerationStrategy sessionIdGenerationStrategy = (SessionIdGenerationStrategy) ReflectionTestUtils
.getField(sessionRepository, "sessionIdGenerationStrategy");
assertThat(sessionIdGenerationStrategy).isInstanceOf(FixedSessionIdGenerationStrategy.class);
}
@Test
void sessionIdGenerationStrategyWhenNoBeanThenDefault() {
registerAndRefresh(DataSourceConfiguration.class, DefaultConfiguration.class);
JdbcIndexedSessionRepository sessionRepository = this.context.getBean(JdbcIndexedSessionRepository.class);
SessionIdGenerationStrategy sessionIdGenerationStrategy = (SessionIdGenerationStrategy) ReflectionTestUtils
.getField(sessionRepository, "sessionIdGenerationStrategy");
assertThat(sessionIdGenerationStrategy).isInstanceOf(UuidSessionIdGenerationStrategy.class);
}
private void registerAndRefresh(Class<?>... annotatedClasses) {
this.context.register(annotatedClasses);
this.context.refresh();
}
@Configuration(proxyBeanMethods = false)
@EnableJdbcHttpSession
static class CustomSessionIdGenerationStrategyConfiguration {
@Bean
SessionIdGenerationStrategy sessionIdGenerationStrategy() {
return new FixedSessionIdGenerationStrategy("my-id");
}
}
@Configuration(proxyBeanMethods = false)
@EnableJdbcHttpSession
static class NoDataSourceConfiguration {