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

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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;
}
}