Introduce SessionIdGenerationStrategy
Closes gh-11
This commit is contained in:
committed by
Marcus Hert Da Coregio
parent
2e1275333a
commit
d547b33962
@@ -74,6 +74,9 @@ public final class MapSession implements Session, Serializable {
|
||||
*/
|
||||
private Duration maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL;
|
||||
|
||||
private transient SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy
|
||||
.getInstance();
|
||||
|
||||
/**
|
||||
* Creates a new instance with a secure randomly generated identifier.
|
||||
*/
|
||||
@@ -81,6 +84,17 @@ public final class MapSession implements Session, Serializable {
|
||||
this(generateId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance using the specified {@link SessionIdGenerationStrategy} to
|
||||
* generate the session id.
|
||||
* @param sessionIdGenerationStrategy the {@link SessionIdGenerationStrategy} to use.
|
||||
* @since 3.2
|
||||
*/
|
||||
public MapSession(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
this(sessionIdGenerationStrategy.generate());
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with the specified id. This is preferred to the default
|
||||
* constructor when the id is known to prevent unnecessary consumption on entropy
|
||||
@@ -141,7 +155,7 @@ public final class MapSession implements Session, Serializable {
|
||||
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
String changedId = generateId();
|
||||
String changedId = this.sessionIdGenerationStrategy.generate();
|
||||
setId(changedId);
|
||||
return changedId;
|
||||
}
|
||||
@@ -232,6 +246,16 @@ public final class MapSession implements Session, Serializable {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SessionIdGenerationStrategy} to use when generating a new session
|
||||
* id.
|
||||
* @param sessionIdGenerationStrategy the {@link SessionIdGenerationStrategy} to use.
|
||||
* @since 3.2
|
||||
*/
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 7160779239673823561L;
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
|
||||
private final Map<String, Session> sessions;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
/**
|
||||
* Creates a new instance backed by the provided {@link java.util.Map}. This allows
|
||||
* injecting a distributed {@link java.util.Map}.
|
||||
@@ -71,7 +73,9 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
if (!session.getId().equals(session.getOriginalId())) {
|
||||
this.sessions.remove(session.getOriginalId());
|
||||
}
|
||||
this.sessions.put(session.getId(), new MapSession(session));
|
||||
MapSession saved = new MapSession(session);
|
||||
saved.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
|
||||
this.sessions.put(session.getId(), saved);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,7 +88,9 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
deleteById(saved.getId());
|
||||
return null;
|
||||
}
|
||||
return new MapSession(saved);
|
||||
MapSession result = new MapSession(saved);
|
||||
result.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,9 +100,14 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
|
||||
@Override
|
||||
public MapSession createSession() {
|
||||
MapSession result = new MapSession();
|
||||
MapSession result = new MapSession(this.sessionIdGenerationStrategy);
|
||||
result.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
Assert.notNull(sessionIdGenerationStrategy, "sessionIdGenerationStrategy cannot be null");
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ public class ReactiveMapSessionRepository implements ReactiveSessionRepository<M
|
||||
|
||||
private final Map<String, Session> sessions;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
/**
|
||||
* Creates a new instance backed by the provided {@link Map}. This allows injecting a
|
||||
* distributed {@link Map}.
|
||||
@@ -84,6 +86,7 @@ public class ReactiveMapSessionRepository implements ReactiveSessionRepository<M
|
||||
return Mono.defer(() -> Mono.justOrEmpty(this.sessions.get(id))
|
||||
.filter((session) -> !session.isExpired())
|
||||
.map(MapSession::new)
|
||||
.doOnNext((session) -> session.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy))
|
||||
.switchIfEmpty(deleteById(id).then(Mono.empty())));
|
||||
// @formatter:on
|
||||
}
|
||||
@@ -96,10 +99,21 @@ public class ReactiveMapSessionRepository implements ReactiveSessionRepository<M
|
||||
@Override
|
||||
public Mono<MapSession> createSession() {
|
||||
return Mono.defer(() -> {
|
||||
MapSession result = new MapSession();
|
||||
MapSession result = new MapSession(this.sessionIdGenerationStrategy);
|
||||
result.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
return Mono.just(result);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SessionIdGenerationStrategy} to use.
|
||||
* @param sessionIdGenerationStrategy the non-null {@link SessionIdGenerationStrategy}
|
||||
* to use
|
||||
* @since 3.2
|
||||
*/
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
Assert.notNull(sessionIdGenerationStrategy, "sessionIdGenerationStrategy cannot be null");
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* An interface for specifying a strategy for generating session identifiers.
|
||||
*
|
||||
* @author Marcus da Coregio
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface SessionIdGenerationStrategy {
|
||||
|
||||
@NonNull
|
||||
String generate();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* A {@link SessionIdGenerationStrategy} that generates a random UUID to be used as the
|
||||
* session id.
|
||||
*
|
||||
* @author Marcus da Coregio
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class UuidSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
private static final UuidSessionIdGenerationStrategy INSTANCE = new UuidSessionIdGenerationStrategy();
|
||||
|
||||
private UuidSessionIdGenerationStrategy() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String generate() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of {@link UuidSessionIdGenerationStrategy}.
|
||||
* @return the singleton instance of {@link UuidSessionIdGenerationStrategy}
|
||||
*/
|
||||
public static UuidSessionIdGenerationStrategy getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package org.springframework.session;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -42,6 +43,19 @@ class MapSessionTests {
|
||||
.withMessage("session cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorWhenSessionIdGenerationStrategyThenUsesStrategy() {
|
||||
MapSession session = new MapSession(new FixedSessionIdGenerationStrategy("my-id"));
|
||||
assertThat(session.getId()).isEqualTo("my-id");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorWhenDefaultThenUuid() {
|
||||
String id = this.session.getId();
|
||||
UUID uuid = UUID.fromString(id);
|
||||
assertThat(uuid).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAttributeWhenNullThenNull() {
|
||||
String result = this.session.getAttribute("attrName");
|
||||
@@ -143,6 +157,41 @@ class MapSessionTests {
|
||||
assertThat(this.session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void changeSessionIdWhenSessionIdStrategyThenUsesStrategy() {
|
||||
MapSession session = new MapSession(new IncrementalSessionIdGenerationStrategy());
|
||||
String idBeforeChange = session.getId();
|
||||
String idAfterChange = session.changeSessionId();
|
||||
assertThat(idBeforeChange).isEqualTo("1");
|
||||
assertThat(idAfterChange).isEqualTo("2");
|
||||
}
|
||||
|
||||
static class FixedSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
private final String id;
|
||||
|
||||
FixedSessionIdGenerationStrategy(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generate() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class IncrementalSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
private int counter = 1;
|
||||
|
||||
@Override
|
||||
public String generate() {
|
||||
return String.valueOf(this.counter++);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CustomSession implements Session {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -152,4 +152,31 @@ class ReactiveMapSessionRepositoryTests {
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createSessionWhenSessionIdGenerationStrategyThenUses() {
|
||||
this.repository.setSessionIdGenerationStrategy(() -> "test");
|
||||
MapSession session = this.repository.createSession().block();
|
||||
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");
|
||||
|
||||
MapSession session = this.repository.createSession().block();
|
||||
this.repository.save(session).block();
|
||||
|
||||
MapSession savedSession = this.repository.findById("test").block();
|
||||
|
||||
assertThat(savedSession.getId()).isEqualTo("test");
|
||||
assertThat(savedSession.changeSessionId()).isEqualTo("test");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ import org.springframework.data.mongodb.core.index.IndexOperations;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.session.events.SessionExpiredEvent;
|
||||
@@ -81,6 +83,8 @@ public class MongoIndexedSessionRepository
|
||||
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
public MongoIndexedSessionRepository(MongoOperations mongoOperations) {
|
||||
this.mongoOperations = mongoOperations;
|
||||
}
|
||||
@@ -88,7 +92,7 @@ public class MongoIndexedSessionRepository
|
||||
@Override
|
||||
public MongoSession createSession() {
|
||||
|
||||
MongoSession session = new MongoSession();
|
||||
MongoSession session = new MongoSession(this.sessionIdGenerationStrategy);
|
||||
|
||||
session.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
|
||||
@@ -116,10 +120,13 @@ public class MongoIndexedSessionRepository
|
||||
|
||||
MongoSession session = MongoSessionUtils.convertToSession(this.mongoSessionConverter, sessionWrapper);
|
||||
|
||||
if (session != null && session.isExpired()) {
|
||||
publishEvent(new SessionExpiredEvent(this, session));
|
||||
deleteById(id);
|
||||
return null;
|
||||
if (session != null) {
|
||||
if (session.isExpired()) {
|
||||
publishEvent(new SessionExpiredEvent(this, session));
|
||||
deleteById(id);
|
||||
return null;
|
||||
}
|
||||
session.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
|
||||
}
|
||||
|
||||
return session;
|
||||
@@ -140,6 +147,7 @@ public class MongoIndexedSessionRepository
|
||||
.map((query) -> this.mongoOperations.find(query, Document.class, this.collectionName))
|
||||
.orElse(Collections.emptyList()).stream()
|
||||
.map((dbSession) -> MongoSessionUtils.convertToSession(this.mongoSessionConverter, dbSession))
|
||||
.peek((session) -> session.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy))
|
||||
.collect(Collectors.toMap(MongoSession::getId, (mapSession) -> mapSession));
|
||||
}
|
||||
|
||||
@@ -216,4 +224,14 @@ public class MongoIndexedSessionRepository
|
||||
this.mongoSessionConverter = mongoSessionConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,12 +23,14 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Session object providing additional information about the datetime of expiration.
|
||||
@@ -66,12 +68,24 @@ class MongoSession implements Session {
|
||||
|
||||
private Map<String, Object> attrs = new HashMap<>();
|
||||
|
||||
private transient SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy
|
||||
.getInstance();
|
||||
|
||||
/**
|
||||
* Constructs a new instance using the provided session id.
|
||||
* @param sessionId the session id to use
|
||||
* @since 3.2
|
||||
*/
|
||||
MongoSession(String sessionId) {
|
||||
this(sessionId, MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
}
|
||||
|
||||
MongoSession() {
|
||||
this(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
}
|
||||
|
||||
MongoSession(long maxInactiveIntervalInSeconds) {
|
||||
this(UUID.randomUUID().toString(), maxInactiveIntervalInSeconds);
|
||||
this(UuidSessionIdGenerationStrategy.getInstance().generate(), maxInactiveIntervalInSeconds);
|
||||
}
|
||||
|
||||
MongoSession(String id, long maxInactiveIntervalInSeconds) {
|
||||
@@ -82,6 +96,28 @@ class MongoSession implements Session {
|
||||
setLastAccessedTime(Instant.ofEpochMilli(this.createdMillis));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance using the provided {@link SessionIdGenerationStrategy}.
|
||||
* @param sessionIdGenerationStrategy the {@link SessionIdGenerationStrategy} to use
|
||||
* @since 3.2
|
||||
*/
|
||||
MongoSession(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
this(sessionIdGenerationStrategy.generate(), MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance using the provided {@link SessionIdGenerationStrategy}
|
||||
* and max inactive interval.
|
||||
* @param sessionIdGenerationStrategy the {@link SessionIdGenerationStrategy} to use
|
||||
* @param maxInactiveIntervalInSeconds the max inactive interval in seconds
|
||||
* @since 3.2
|
||||
*/
|
||||
MongoSession(SessionIdGenerationStrategy sessionIdGenerationStrategy, long maxInactiveIntervalInSeconds) {
|
||||
this(sessionIdGenerationStrategy.generate(), maxInactiveIntervalInSeconds);
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
static String coverDot(String attributeName) {
|
||||
return attributeName.replace('.', DOT_COVER_CHAR);
|
||||
}
|
||||
@@ -93,7 +129,7 @@ class MongoSession implements Session {
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
|
||||
String changedId = UUID.randomUUID().toString();
|
||||
String changedId = this.sessionIdGenerationStrategy.generate();
|
||||
this.id = changedId;
|
||||
return changedId;
|
||||
}
|
||||
@@ -141,7 +177,6 @@ class MongoSession implements Session {
|
||||
|
||||
@Override
|
||||
public void setLastAccessedTime(Instant lastAccessedTime) {
|
||||
|
||||
this.accessedMillis = lastAccessedTime.toEpochMilli();
|
||||
this.expireAt = Date.from(lastAccessedTime.plus(Duration.ofSeconds(this.intervalSeconds)));
|
||||
}
|
||||
@@ -200,4 +235,23 @@ class MongoSession implements Session {
|
||||
return this.originalSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session id.
|
||||
* @param id the id to set
|
||||
* @since 3.2
|
||||
*/
|
||||
void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SessionIdGenerationStrategy} to use.
|
||||
* @param sessionIdGenerationStrategy the {@link SessionIdGenerationStrategy} to use
|
||||
* @since 3.2
|
||||
*/
|
||||
void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
Assert.notNull(sessionIdGenerationStrategy, "sessionIdGenerationStrategy cannot be null");
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.bson.Document;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
@@ -34,6 +35,8 @@ import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -76,6 +79,8 @@ public class ReactiveMongoSessionRepository
|
||||
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
public ReactiveMongoSessionRepository(ReactiveMongoOperations mongoOperations) {
|
||||
this.mongoOperations = mongoOperations;
|
||||
}
|
||||
@@ -93,11 +98,17 @@ public class ReactiveMongoSessionRepository
|
||||
*/
|
||||
@Override
|
||||
public Mono<MongoSession> createSession() {
|
||||
|
||||
return Mono.justOrEmpty(this.defaultMaxInactiveInterval.toSeconds()) //
|
||||
.map(MongoSession::new) //
|
||||
.doOnNext((mongoSession) -> publishEvent(new SessionCreatedEvent(this, mongoSession))) //
|
||||
.switchIfEmpty(Mono.just(new MongoSession()));
|
||||
// @formatter:off
|
||||
return Mono.fromSupplier(() -> this.sessionIdGenerationStrategy.generate())
|
||||
.map(MongoSession::new)
|
||||
.doOnNext((mongoSession) -> mongoSession.setMaxInactiveInterval(this.defaultMaxInactiveInterval))
|
||||
.doOnNext(
|
||||
(mongoSession) -> mongoSession.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy))
|
||||
.doOnNext((mongoSession) -> publishEvent(new SessionCreatedEvent(this, mongoSession)))
|
||||
.switchIfEmpty(Mono.just(new MongoSession(this.sessionIdGenerationStrategy)))
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.publishOn(Schedulers.parallel());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,6 +138,8 @@ public class ReactiveMongoSessionRepository
|
||||
return findSession(id) //
|
||||
.map((document) -> MongoSessionUtils.convertToSession(this.mongoSessionConverter, document)) //
|
||||
.filter((mongoSession) -> !mongoSession.isExpired()) //
|
||||
.doOnNext(
|
||||
(mongoSession) -> mongoSession.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy))
|
||||
.switchIfEmpty(Mono.defer(() -> this.deleteById(id).then(Mono.empty())));
|
||||
}
|
||||
|
||||
@@ -216,4 +229,9 @@ public class ReactiveMongoSessionRepository
|
||||
this.blockingMongoOperations = blockingMongoOperations;
|
||||
}
|
||||
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
Assert.notNull(sessionIdGenerationStrategy, "sessionIdGenerationStrategy cannot be null");
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.MapSession;
|
||||
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.data.mongo.AbstractMongoSessionConverter;
|
||||
@@ -70,6 +72,8 @@ public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, Embe
|
||||
|
||||
private IndexResolver<Session> indexResolver;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
@Bean
|
||||
public MongoIndexedSessionRepository mongoSessionRepository(MongoOperations mongoOperations) {
|
||||
|
||||
@@ -98,6 +102,7 @@ public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, Embe
|
||||
if (StringUtils.hasText(this.collectionName)) {
|
||||
repository.setCollectionName(this.collectionName);
|
||||
}
|
||||
repository.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
|
||||
|
||||
this.sessionRepositoryCustomizers
|
||||
.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(repository));
|
||||
@@ -160,4 +165,9 @@ public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, Embe
|
||||
this.indexResolver = indexResolver;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.session.config.ReactiveSessionRepositoryCustomizer;
|
||||
import org.springframework.session.config.annotation.web.server.SpringWebSessionConfiguration;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
@@ -74,6 +76,8 @@ public class ReactiveMongoWebSessionConfiguration
|
||||
|
||||
private IndexResolver<Session> indexResolver;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
@Bean
|
||||
public ReactiveMongoSessionRepository reactiveMongoSessionRepository(ReactiveMongoOperations operations) {
|
||||
|
||||
@@ -112,6 +116,8 @@ public class ReactiveMongoWebSessionConfiguration
|
||||
this.sessionRepositoryCustomizers
|
||||
.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(repository));
|
||||
|
||||
repository.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
|
||||
|
||||
return repository;
|
||||
}
|
||||
|
||||
@@ -180,4 +186,9 @@ public class ReactiveMongoWebSessionConfiguration
|
||||
this.indexResolver = indexResolver;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,8 +34,10 @@ import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -209,4 +211,52 @@ public class MongoIndexedSessionRepositoryTest {
|
||||
assertThat(sessionsMap).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createSessionWhenSessionIdGenerationStrategyThenUses() {
|
||||
this.repository.setSessionIdGenerationStrategy(new FixedSessionIdGenerationStrategy("123"));
|
||||
MongoSession session = this.repository.createSession();
|
||||
assertThat(session.getId()).isEqualTo("123");
|
||||
assertThat(session.changeSessionId()).isEqualTo("123");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setSessionIdGenerationStrategyWhenNullThenThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setSessionIdGenerationStrategy(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByIdWhenChangeSessionIdThenUsesSessionIdGenerationStrategy() {
|
||||
this.repository.setSessionIdGenerationStrategy(new FixedSessionIdGenerationStrategy("456"));
|
||||
|
||||
Document sessionDocument = new Document();
|
||||
|
||||
given(this.mongoOperations.findById("123", Document.class,
|
||||
MongoIndexedSessionRepository.DEFAULT_COLLECTION_NAME)).willReturn(sessionDocument);
|
||||
|
||||
MongoSession session = new MongoSession("123");
|
||||
|
||||
given(this.converter.convert(sessionDocument, TypeDescriptor.valueOf(Document.class),
|
||||
TypeDescriptor.valueOf(MongoSession.class))).willReturn(session);
|
||||
|
||||
MongoSession retrievedSession = this.repository.findById("123");
|
||||
assertThat(retrievedSession.getId()).isEqualTo("123");
|
||||
String newSessionId = retrievedSession.changeSessionId();
|
||||
assertThat(newSessionId).isEqualTo("456");
|
||||
}
|
||||
|
||||
static class FixedSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
private final String id;
|
||||
|
||||
FixedSessionIdGenerationStrategy(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generate() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.session.MapSession;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.BDDMockito.any;
|
||||
import static org.mockito.BDDMockito.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -210,4 +211,43 @@ public class ReactiveMongoSessionRepositoryTest {
|
||||
verify(this.converter, times(1)).ensureIndexes(indexOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createSessionWhenSessionIdGenerationStrategyThenUses() {
|
||||
this.repository.setSessionIdGenerationStrategy(() -> "test");
|
||||
|
||||
this.repository.createSession().as(StepVerifier::create).assertNext((mongoSession) -> {
|
||||
assertThat(mongoSession.getId()).isEqualTo("test");
|
||||
assertThat(mongoSession.changeSessionId()).isEqualTo("test");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setSessionIdGenerationStrategyWhenNullThenThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setSessionIdGenerationStrategy(null))
|
||||
.withMessage("sessionIdGenerationStrategy cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByIdWhenChangeSessionIdThenUsesSessionIdGenerationStrategy() {
|
||||
this.repository.setSessionIdGenerationStrategy(() -> "test");
|
||||
|
||||
String sessionId = UUID.randomUUID().toString();
|
||||
Document sessionDocument = new Document();
|
||||
|
||||
given(this.mongoOperations.findById(sessionId, Document.class,
|
||||
ReactiveMongoSessionRepository.DEFAULT_COLLECTION_NAME)).willReturn(Mono.just(sessionDocument));
|
||||
|
||||
MongoSession session = new MongoSession(sessionId);
|
||||
|
||||
given(this.converter.convert(sessionDocument, TypeDescriptor.valueOf(Document.class),
|
||||
TypeDescriptor.valueOf(MongoSession.class))).willReturn(session);
|
||||
|
||||
this.repository.findById(sessionId).as(StepVerifier::create).assertNext((mongoSession) -> {
|
||||
String oldId = mongoSession.getId();
|
||||
String newId = mongoSession.changeSessionId();
|
||||
assertThat(oldId).isEqualTo(sessionId);
|
||||
assertThat(newId).isEqualTo("test");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ import org.springframework.data.mongodb.core.index.IndexOperations;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.session.IndexResolver;
|
||||
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.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.JacksonMongoSessionConverter;
|
||||
@@ -200,6 +202,22 @@ public class MongoHttpSessionConfigurationTest {
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenSessionIdGenerationStrategyBeanThenUses() {
|
||||
registerAndRefresh(SessionIdGenerationStrategyConfiguration.class);
|
||||
MongoIndexedSessionRepository sessionRepository = this.context.getBean(MongoIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(TestSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenNoSessionIdGenerationStrategyBeanThenDefault() {
|
||||
registerAndRefresh(DefaultConfiguration.class);
|
||||
MongoIndexedSessionRepository sessionRepository = this.context.getBean(MongoIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(UuidSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
|
||||
this.context.register(annotatedClasses);
|
||||
@@ -350,4 +368,25 @@ public class MongoHttpSessionConfigurationTest {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoHttpSession
|
||||
@Import(MongoConfiguration.class)
|
||||
static class SessionIdGenerationStrategyConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionIdGenerationStrategy sessionIdGenerationStrategy() {
|
||||
return new TestSessionIdGenerationStrategy();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
@Override
|
||||
public String generate() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ import org.springframework.data.mongodb.core.index.IndexOperations;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.session.config.ReactiveSessionRepositoryCustomizer;
|
||||
import org.springframework.session.config.annotation.web.server.EnableSpringWebSession;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
@@ -222,6 +224,28 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenSessionIdGenerationStrategyBeanThenUses() {
|
||||
registerAndRefresh(GoodConfig.class, SessionIdGenerationStrategyConfiguration.class);
|
||||
ReactiveMongoSessionRepository sessionRepository = this.context.getBean(ReactiveMongoSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(TestSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenNoSessionIdGenerationStrategyBeanThenDefault() {
|
||||
registerAndRefresh(GoodConfig.class);
|
||||
ReactiveMongoSessionRepository sessionRepository = this.context.getBean(ReactiveMongoSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(UuidSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reflectively extract the {@link AbstractMongoSessionConverter} from the
|
||||
* {@link ReactiveMongoSessionRepository}. This is to avoid expanding the surface area
|
||||
@@ -411,4 +435,23 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SessionIdGenerationStrategyConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionIdGenerationStrategy sessionIdGenerationStrategy() {
|
||||
return new TestSessionIdGenerationStrategy();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
@Override
|
||||
public String generate() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ import org.springframework.session.MapSession;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
import org.springframework.session.SaveMode;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -61,6 +63,8 @@ public class ReactiveRedisSessionRepository
|
||||
|
||||
private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveRedisSessionRepository} instance.
|
||||
* @param sessionRedisOperations the {@link ReactiveRedisOperations} to use for
|
||||
@@ -120,7 +124,7 @@ public class ReactiveRedisSessionRepository
|
||||
@Override
|
||||
public Mono<RedisSession> createSession() {
|
||||
return Mono.defer(() -> {
|
||||
MapSession cached = new MapSession();
|
||||
MapSession cached = new MapSession(this.sessionIdGenerationStrategy);
|
||||
cached.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
RedisSession session = new RedisSession(cached, true);
|
||||
return Mono.just(session);
|
||||
@@ -167,6 +171,16 @@ public class ReactiveRedisSessionRepository
|
||||
return this.namespace + "sessions:" + sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom implementation of {@link Session} that uses a {@link MapSession} as the
|
||||
* basis for its mapping. It keeps track of any attributes that have changed. When
|
||||
@@ -206,7 +220,9 @@ public class ReactiveRedisSessionRepository
|
||||
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
return this.cached.changeSessionId();
|
||||
String newSessionId = ReactiveRedisSessionRepository.this.sessionIdGenerationStrategy.generate();
|
||||
this.cached.setId(newSessionId);
|
||||
return newSessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -52,6 +52,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.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.session.events.SessionDestroyedEvent;
|
||||
@@ -322,6 +324,8 @@ public class RedisIndexedSessionRepository
|
||||
|
||||
private ThreadPoolTaskScheduler taskScheduler;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
/**
|
||||
* Creates a new instance. For an example, refer to the class level javadoc.
|
||||
* @param sessionRedisOperations the {@link RedisOperations} to use for managing the
|
||||
@@ -547,7 +551,7 @@ public class RedisIndexedSessionRepository
|
||||
|
||||
@Override
|
||||
public RedisSession createSession() {
|
||||
MapSession cached = new MapSession();
|
||||
MapSession cached = new MapSession(this.sessionIdGenerationStrategy);
|
||||
cached.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
RedisSession session = new RedisSession(cached, true);
|
||||
session.flushImmediateIfNecessary();
|
||||
@@ -716,6 +720,16 @@ public class RedisIndexedSessionRepository
|
||||
return RedisSessionMapper.ATTRIBUTE_PREFIX + attributeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom implementation of {@link Session} that uses a {@link MapSession} as the
|
||||
* basis for its mapping. It keeps track of any attributes that have changed. When
|
||||
@@ -780,7 +794,9 @@ public class RedisIndexedSessionRepository
|
||||
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
return this.cached.changeSessionId();
|
||||
String newSessionId = RedisIndexedSessionRepository.this.sessionIdGenerationStrategy.generate();
|
||||
this.cached.setId(newSessionId);
|
||||
return newSessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,9 @@ import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.SaveMode;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -56,6 +58,8 @@ public class RedisSessionRepository implements SessionRepository<RedisSessionRep
|
||||
|
||||
private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
/**
|
||||
* Create a new {@link RedisSessionRepository} instance.
|
||||
* @param sessionRedisOperations the {@link RedisOperations} to use for managing
|
||||
@@ -106,7 +110,7 @@ public class RedisSessionRepository implements SessionRepository<RedisSessionRep
|
||||
|
||||
@Override
|
||||
public RedisSession createSession() {
|
||||
MapSession cached = new MapSession();
|
||||
MapSession cached = new MapSession(this.sessionIdGenerationStrategy);
|
||||
cached.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
RedisSession session = new RedisSession(cached, true);
|
||||
session.flushIfRequired();
|
||||
@@ -162,6 +166,16 @@ public class RedisSessionRepository implements SessionRepository<RedisSessionRep
|
||||
return RedisSessionMapper.ATTRIBUTE_PREFIX + attributeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal {@link Session} implementation used by this {@link SessionRepository}.
|
||||
*/
|
||||
@@ -198,7 +212,9 @@ public class RedisSessionRepository implements SessionRepository<RedisSessionRep
|
||||
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
return this.cached.changeSessionId();
|
||||
String newSessionId = RedisSessionRepository.this.sessionIdGenerationStrategy.generate();
|
||||
this.cached.setId(newSessionId);
|
||||
return newSessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.session.data.redis.config.annotation.web.http;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -27,6 +28,8 @@ import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.session.data.redis.RedisSessionRepository;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -49,6 +52,8 @@ public class RedisHttpSessionConfiguration extends AbstractRedisHttpSessionConfi
|
||||
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public RedisSessionRepository sessionRepository() {
|
||||
@@ -60,6 +65,7 @@ public class RedisHttpSessionConfiguration extends AbstractRedisHttpSessionConfi
|
||||
}
|
||||
sessionRepository.setFlushMode(getFlushMode());
|
||||
sessionRepository.setSaveMode(getSaveMode());
|
||||
sessionRepository.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
|
||||
getSessionRepositoryCustomizers()
|
||||
.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(sessionRepository));
|
||||
return sessionRepository;
|
||||
@@ -87,4 +93,9 @@ public class RedisHttpSessionConfiguration extends AbstractRedisHttpSessionConfi
|
||||
setSaveMode(attributes.getEnum("saveMode"));
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ import org.springframework.data.redis.listener.PatternTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.session.data.redis.RedisIndexedSessionRepository;
|
||||
import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction;
|
||||
import org.springframework.session.data.redis.config.ConfigureRedisAction;
|
||||
@@ -80,6 +82,8 @@ public class RedisIndexedHttpSessionConfiguration
|
||||
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public RedisIndexedSessionRepository sessionRepository() {
|
||||
@@ -101,6 +105,7 @@ public class RedisIndexedHttpSessionConfiguration
|
||||
sessionRepository.setCleanupCron(this.cleanupCron);
|
||||
int database = resolveDatabase();
|
||||
sessionRepository.setDatabase(database);
|
||||
sessionRepository.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
|
||||
getSessionRepositoryCustomizers()
|
||||
.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(sessionRepository));
|
||||
return sessionRepository;
|
||||
@@ -204,6 +209,11 @@ public class RedisIndexedHttpSessionConfiguration
|
||||
return RedisIndexedSessionRepository.DEFAULT_DATABASE;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that Redis is configured to send keyspace notifications. This is important
|
||||
* to ensure that expiration and deletion of sessions trigger SessionDestroyedEvents.
|
||||
|
||||
@@ -39,6 +39,8 @@ import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.SaveMode;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.session.config.ReactiveSessionRepositoryCustomizer;
|
||||
import org.springframework.session.config.annotation.web.server.SpringWebSessionConfiguration;
|
||||
import org.springframework.session.data.redis.ReactiveRedisSessionRepository;
|
||||
@@ -77,6 +79,8 @@ public class RedisWebSessionConfiguration implements BeanClassLoaderAware, Embed
|
||||
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
@Bean
|
||||
public ReactiveRedisSessionRepository sessionRepository() {
|
||||
ReactiveRedisTemplate<String, Object> reactiveRedisTemplate = createReactiveRedisTemplate();
|
||||
@@ -86,6 +90,7 @@ public class RedisWebSessionConfiguration implements BeanClassLoaderAware, Embed
|
||||
sessionRepository.setRedisKeyNamespace(this.redisNamespace);
|
||||
}
|
||||
sessionRepository.setSaveMode(this.saveMode);
|
||||
sessionRepository.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
|
||||
this.sessionRepositoryCustomizers
|
||||
.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(sessionRepository));
|
||||
return sessionRepository;
|
||||
@@ -168,4 +173,9 @@ public class RedisWebSessionConfiguration implements BeanClassLoaderAware, Embed
|
||||
return new ReactiveRedisTemplate<>(this.redisConnectionFactory, serializationContext);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -438,6 +438,46 @@ class ReactiveRedisSessionRepositoryTests {
|
||||
verifyNoMoreInteractions(this.hashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createSessionWhenSessionIdGenerationStrategyThenUses() {
|
||||
this.repository.setSessionIdGenerationStrategy(() -> "test");
|
||||
|
||||
this.repository.createSession().as(StepVerifier::create).assertNext((redisSession) -> {
|
||||
assertThat(redisSession.getId()).isEqualTo("test");
|
||||
assertThat(redisSession.changeSessionId()).isEqualTo("test");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setSessionIdGenerationStrategyWhenNullThenThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setSessionIdGenerationStrategy(null))
|
||||
.withMessage("sessionIdGenerationStrategy cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void findByIdWhenChangeSessionIdThenUsesSessionIdGenerationStrategy() {
|
||||
this.repository.setSessionIdGenerationStrategy(() -> "changed-session-id");
|
||||
given(this.redisOperations.opsForHash()).willReturn(this.hashOperations);
|
||||
String attribute1 = "attribute1";
|
||||
String attribute2 = "attribute2";
|
||||
MapSession expected = new MapSession("test");
|
||||
expected.setLastAccessedTime(Instant.now().minusSeconds(60));
|
||||
expected.setAttribute(attribute1, "test");
|
||||
expected.setAttribute(attribute2, null);
|
||||
Map map = map(RedisSessionMapper.ATTRIBUTE_PREFIX + attribute1, expected.getAttribute(attribute1),
|
||||
RedisSessionMapper.ATTRIBUTE_PREFIX + attribute2, expected.getAttribute(attribute2),
|
||||
RedisSessionMapper.CREATION_TIME_KEY, expected.getCreationTime().toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, (int) expected.getMaxInactiveInterval().getSeconds(),
|
||||
RedisSessionMapper.LAST_ACCESSED_TIME_KEY, expected.getLastAccessedTime().toEpochMilli());
|
||||
given(this.hashOperations.entries(anyString())).willReturn(Flux.fromIterable(map.entrySet()));
|
||||
|
||||
StepVerifier.create(this.repository.findById("test")).consumeNextWith((session) -> {
|
||||
assertThat(session.getId()).isEqualTo(expected.getId());
|
||||
assertThat(session.changeSessionId()).isEqualTo("changed-session-id");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
private Map<String, Object> map(Object... objects) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
if (objects == null) {
|
||||
|
||||
@@ -910,6 +910,46 @@ class RedisIndexedSessionRepositoryTests {
|
||||
assertThat(getDelta()).hasSize(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createSessionWhenSessionIdGenerationStrategyThenUses() {
|
||||
this.redisRepository.setSessionIdGenerationStrategy(() -> "test");
|
||||
RedisSession session = this.redisRepository.createSession();
|
||||
assertThat(session.getId()).isEqualTo("test");
|
||||
assertThat(session.changeSessionId()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setSessionIdGenerationStrategyWhenNullThenThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.redisRepository.setSessionIdGenerationStrategy(null))
|
||||
.withMessage("sessionIdGenerationStrategy cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByIdWhenChangeSessionIdThenUsesSessionIdGenerationStrategy() {
|
||||
this.redisRepository.setSessionIdGenerationStrategy(() -> "test");
|
||||
String attribute1 = "attribute1";
|
||||
String attribute2 = "attribute2";
|
||||
MapSession expected = new MapSession("original");
|
||||
expected.setLastAccessedTime(Instant.now().minusSeconds(60));
|
||||
expected.setAttribute(attribute1, "test");
|
||||
expected.setAttribute(attribute2, null);
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(expected.getId())))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map<String, Object> map = map(RedisIndexedSessionRepository.getSessionAttrNameKey(attribute1),
|
||||
expected.getAttribute(attribute1), RedisIndexedSessionRepository.getSessionAttrNameKey(attribute2),
|
||||
expected.getAttribute(attribute2), RedisSessionMapper.CREATION_TIME_KEY,
|
||||
expected.getCreationTime().toEpochMilli(), RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY,
|
||||
(int) expected.getMaxInactiveInterval().getSeconds(), RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
expected.getLastAccessedTime().toEpochMilli());
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
|
||||
RedisSession session = this.redisRepository.findById(expected.getId());
|
||||
String oldSessionId = session.getId();
|
||||
String newSessionId = session.changeSessionId();
|
||||
assertThat(oldSessionId).isEqualTo("original");
|
||||
assertThat(newSessionId).isEqualTo("test");
|
||||
}
|
||||
|
||||
private String getKey(String id) {
|
||||
return "spring:session:sessions:" + id;
|
||||
}
|
||||
|
||||
@@ -373,6 +373,35 @@ class RedisSessionRepositoryTests {
|
||||
verifyNoMoreInteractions(this.sessionHashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createSessionWhenSessionIdGenerationStrategyThenUses() {
|
||||
this.sessionRepository.setSessionIdGenerationStrategy(() -> "test");
|
||||
RedisSessionRepository.RedisSession session = this.sessionRepository.createSession();
|
||||
assertThat(session.getId()).isEqualTo("test");
|
||||
assertThat(session.changeSessionId()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setSessionIdGenerationStrategyWhenNullThenThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.sessionRepository.setSessionIdGenerationStrategy(null))
|
||||
.withMessage("sessionIdGenerationStrategy cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByIdWhenChangeSessionIdThenUsesSessionIdGenerationStrategy() {
|
||||
this.sessionRepository.setSessionIdGenerationStrategy(() -> "test");
|
||||
Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
||||
given(this.sessionHashOperations.entries(eq(TEST_SESSION_KEY)))
|
||||
.willReturn(mapOf(RedisSessionMapper.CREATION_TIME_KEY, Instant.EPOCH.toEpochMilli(),
|
||||
RedisSessionMapper.LAST_ACCESSED_TIME_KEY, now.toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS,
|
||||
RedisSessionMapper.ATTRIBUTE_PREFIX + "attribute1", "value1"));
|
||||
RedisSession session = this.sessionRepository.findById(TEST_SESSION_ID);
|
||||
assertThat(session.getId()).isEqualTo(TEST_SESSION_ID);
|
||||
assertThat(session.changeSessionId()).isEqualTo("test");
|
||||
}
|
||||
|
||||
private static String getSessionKey(String sessionId) {
|
||||
return "spring:session:sessions:" + sessionId;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.SaveMode;
|
||||
import org.springframework.session.SessionIdGenerationStrategy;
|
||||
import org.springframework.session.UuidSessionIdGenerationStrategy;
|
||||
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||
import org.springframework.session.data.redis.RedisSessionRepository;
|
||||
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisConnectionFactory;
|
||||
@@ -206,6 +208,22 @@ class RedisHttpsSessionConfigurationTests {
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenSessionIdGenerationStrategyBeanThenUses() {
|
||||
registerAndRefresh(RedisConfig.class, SessionIdGenerationStrategyConfiguration.class);
|
||||
RedisSessionRepository sessionRepository = this.context.getBean(RedisSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(TestSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenNoSessionIdGenerationStrategyBeanThenDefault() {
|
||||
registerAndRefresh(RedisConfig.class, DefaultConfiguration.class);
|
||||
RedisSessionRepository sessionRepository = this.context.getBean(RedisSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(UuidSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
@@ -381,4 +399,30 @@ class RedisHttpsSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisHttpSession
|
||||
static class SessionIdGenerationStrategyConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionIdGenerationStrategy sessionIdGenerationStrategy() {
|
||||
return new TestSessionIdGenerationStrategy();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisHttpSession
|
||||
static class DefaultConfiguration {
|
||||
|
||||
}
|
||||
|
||||
static class TestSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
@Override
|
||||
public String generate() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ 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.data.redis.RedisIndexedSessionRepository;
|
||||
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisConnectionFactory;
|
||||
@@ -240,6 +242,22 @@ class RedisIndexedHttpSessionConfigurationTests {
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenSessionIdGenerationStrategyBeanThenUses() {
|
||||
registerAndRefresh(RedisConfig.class, SessionIdGenerationStrategyConfiguration.class);
|
||||
RedisIndexedSessionRepository sessionRepository = this.context.getBean(RedisIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(TestSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenNoSessionIdGenerationStrategyBeanThenDefault() {
|
||||
registerAndRefresh(RedisConfig.class, DefaultConfiguration.class);
|
||||
RedisIndexedSessionRepository sessionRepository = this.context.getBean(RedisIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(UuidSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
@@ -444,4 +462,30 @@ class RedisIndexedHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisIndexedHttpSession
|
||||
static class SessionIdGenerationStrategyConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionIdGenerationStrategy sessionIdGenerationStrategy() {
|
||||
return new TestSessionIdGenerationStrategy();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisIndexedHttpSession
|
||||
static class DefaultConfiguration {
|
||||
|
||||
}
|
||||
|
||||
static class TestSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
@Override
|
||||
public String generate() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
** XML Configuration
|
||||
* xref:configurations.adoc[Configurations]
|
||||
** xref:configuration/redis.adoc[Redis]
|
||||
** xref:configuration/common.adoc[Common Configurations]
|
||||
* xref:http-session.adoc[HttpSession Integration]
|
||||
* xref:web-socket.adoc[WebSocket Integration]
|
||||
* xref:web-session.adoc[WebSession Integration]
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
[[common-configurations]]
|
||||
= Common Configurations
|
||||
|
||||
This section contains common configurations that applies to all or most Spring Session modules.
|
||||
It contains configuration examples for the following use cases:
|
||||
|
||||
- I need to <<changing-how-session-ids-are-generated,change the way that Session IDs are generated>>
|
||||
|
||||
[[changing-how-session-ids-are-generated]]
|
||||
== Changing How Session IDs Are Generated
|
||||
|
||||
By default, Spring Session uses `UuidSessionIdGenerationStrategy` which, in turn, uses a `java.util.UUID` to generate a session id.
|
||||
There might be scenarios where it may be better to include other characters to increase entropy, or you may want to use a different algorithm to generate the session id.
|
||||
To change this, you can provide a custom `SessionIdGenerationStrategy` bean:
|
||||
|
||||
.Changing How Session IDs Are Generated
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
public SessionIdGenerationStrategy sessionIdGenerationStrategy() {
|
||||
return new MySessionIdGenerationStrategy();
|
||||
}
|
||||
|
||||
class MySessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
@Override
|
||||
public String generate() {
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
After exposing your `SessionIdGenerationStrategy` bean, Spring Session will use it to generate session ids.
|
||||
|
||||
If you are manually configuring your `SessionRepository` bean (instead of using `@EnableRedisHttpSession`, for example), you can set the `SessionIdGenerationStrategy` directly on the `SessionRepository` implementation:
|
||||
|
||||
.Setting `SessionIdGenerationStrategy` directly into `SessionRepository` implementation
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
public RedisSessionRepository redisSessionRepository(RedisOperations redisOperations) {
|
||||
RedisSessionRepository repository = new RedisSessionRepository(redisOperations)
|
||||
repository.setSessionIdGenerationStrategy(new MySessionIdGenerationStrategy());
|
||||
return repository;
|
||||
}
|
||||
----
|
||||
======
|
||||
@@ -1 +1,3 @@
|
||||
= What's New
|
||||
|
||||
- xref:configuration/common.adoc#changing-how-session-ids-are-generated[docs] - https://github.com/spring-projects/spring-session/issues/11[gh-11] - Introduce `SessionIdGenerationStrategy` to allow custom session id generation
|
||||
|
||||
@@ -48,6 +48,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.session.events.AbstractSessionEvent;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
@@ -151,6 +153,8 @@ public class HazelcastIndexedSessionRepository
|
||||
|
||||
private UUID sessionListenerId;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
/**
|
||||
* Create a new {@link HazelcastIndexedSessionRepository} instance.
|
||||
* @param hazelcastInstance the {@link HazelcastInstance} to use for managing sessions
|
||||
@@ -245,7 +249,7 @@ public class HazelcastIndexedSessionRepository
|
||||
|
||||
@Override
|
||||
public HazelcastSession createSession() {
|
||||
MapSession cached = new MapSession();
|
||||
MapSession cached = new MapSession(this.sessionIdGenerationStrategy);
|
||||
cached.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
HazelcastSession session = new HazelcastSession(cached, true);
|
||||
session.flushImmediateIfNecessary();
|
||||
@@ -349,6 +353,16 @@ public class HazelcastIndexedSessionRepository
|
||||
this.eventPublisher.publishEvent(new SessionExpiredEvent(this, event.getOldValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom implementation of {@link Session} that uses a {@link MapSession} as the
|
||||
* basis for its mapping. It keeps track if changes have been made since last save.
|
||||
@@ -405,7 +419,8 @@ public class HazelcastIndexedSessionRepository
|
||||
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
String newSessionId = this.delegate.changeSessionId();
|
||||
String newSessionId = HazelcastIndexedSessionRepository.this.sessionIdGenerationStrategy.generate();
|
||||
this.delegate.setId(newSessionId);
|
||||
this.sessionIdChanged = true;
|
||||
return newSessionId;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,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.hazelcast.HazelcastIndexedSessionRepository;
|
||||
@@ -75,6 +77,8 @@ public class HazelcastHttpSessionConfiguration implements ImportAware {
|
||||
|
||||
private List<SessionRepositoryCustomizer<HazelcastIndexedSessionRepository>> sessionRepositoryCustomizers;
|
||||
|
||||
private SessionIdGenerationStrategy sessionIdGenerationStrategy = UuidSessionIdGenerationStrategy.getInstance();
|
||||
|
||||
@Bean
|
||||
public FindByIndexNameSessionRepository<?> sessionRepository() {
|
||||
return createHazelcastIndexedSessionRepository();
|
||||
@@ -158,9 +162,15 @@ public class HazelcastHttpSessionConfiguration implements ImportAware {
|
||||
sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveInterval);
|
||||
sessionRepository.setFlushMode(this.flushMode);
|
||||
sessionRepository.setSaveMode(this.saveMode);
|
||||
sessionRepository.setSessionIdGenerationStrategy(this.sessionIdGenerationStrategy);
|
||||
this.sessionRepositoryCustomizers
|
||||
.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(sessionRepository));
|
||||
return sessionRepository;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setSessionIdGenerationStrategy(SessionIdGenerationStrategy sessionIdGenerationStrategy) {
|
||||
this.sessionIdGenerationStrategy = sessionIdGenerationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -465,4 +465,31 @@ class HazelcastIndexedSessionRepositoryTests {
|
||||
verifyNoMoreInteractions(this.sessions);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createSessionWhenSessionIdGenerationStrategyThenUses() {
|
||||
this.repository.setSessionIdGenerationStrategy(() -> "test");
|
||||
HazelcastSession 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");
|
||||
MapSession saved = new MapSession("original");
|
||||
saved.setAttribute("savedName", "savedValue");
|
||||
given(this.sessions.get(eq(saved.getId()))).willReturn(saved);
|
||||
|
||||
HazelcastSession session = this.repository.findById(saved.getId());
|
||||
|
||||
assertThat(session.getId()).isEqualTo(saved.getId());
|
||||
assertThat(session.changeSessionId()).isEqualTo("test");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ 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.hazelcast.HazelcastIndexedSessionRepository;
|
||||
import org.springframework.session.hazelcast.config.annotation.SpringSessionHazelcastInstance;
|
||||
@@ -238,6 +240,24 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenSessionIdGenerationStrategyBeanThenUses() {
|
||||
registerAndRefresh(DefaultConfiguration.class, SessionIdGenerationStrategyConfiguration.class);
|
||||
HazelcastIndexedSessionRepository sessionRepository = this.context
|
||||
.getBean(HazelcastIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(TestSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenNoSessionIdGenerationStrategyBeanThenDefault() {
|
||||
registerAndRefresh(DefaultConfiguration.class);
|
||||
HazelcastIndexedSessionRepository sessionRepository = this.context
|
||||
.getBean(HazelcastIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("sessionIdGenerationStrategy")
|
||||
.isInstanceOf(UuidSessionIdGenerationStrategy.class);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
@@ -465,4 +485,23 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SessionIdGenerationStrategyConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionIdGenerationStrategy sessionIdGenerationStrategy() {
|
||||
return new TestSessionIdGenerationStrategy();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestSessionIdGenerationStrategy implements SessionIdGenerationStrategy {
|
||||
|
||||
@Override
|
||||
public String generate() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user