Add Session.changeSessionId
This commit is contained in:
@@ -39,7 +39,7 @@ import org.springframework.session.events.SessionExpiredEvent;
|
||||
* @author Rob Winch
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MapReactorSessionRepository implements ReactorSessionRepository<Session> {
|
||||
public class MapReactorSessionRepository implements ReactorSessionRepository<MapSession> {
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link Session#setMaxInactiveInterval(Duration)}.
|
||||
@@ -80,7 +80,7 @@ public class MapReactorSessionRepository implements ReactorSessionRepository<Ses
|
||||
}
|
||||
this.sessions = new ConcurrentHashMap<>();
|
||||
for (Session session : sessions) {
|
||||
this.performSave(session);
|
||||
this.performSave(new MapSession(session));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public class MapReactorSessionRepository implements ReactorSessionRepository<Ses
|
||||
}
|
||||
this.sessions = new ConcurrentHashMap<>();
|
||||
for (Session session : sessions) {
|
||||
this.performSave(session);
|
||||
this.performSave(new MapSession(session));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,15 +110,19 @@ public class MapReactorSessionRepository implements ReactorSessionRepository<Ses
|
||||
this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval);
|
||||
}
|
||||
|
||||
public Mono<Void> save(Session session) {
|
||||
public Mono<Void> save(MapSession session) {
|
||||
return Mono.fromRunnable(() -> performSave(session));
|
||||
}
|
||||
|
||||
private void performSave(Session session) {
|
||||
private void performSave(MapSession session) {
|
||||
if (!session.getId().equals(session.getOriginalId())) {
|
||||
this.sessions.remove(session.getOriginalId());
|
||||
session.setOriginalId(session.getId());
|
||||
}
|
||||
this.sessions.put(session.getId(), new MapSession(session));
|
||||
}
|
||||
|
||||
public Mono<Session> findById(String id) {
|
||||
public Mono<MapSession> findById(String id) {
|
||||
return Mono.defer(() -> {
|
||||
Session saved = this.sessions.get(id);
|
||||
if (saved == null) {
|
||||
@@ -136,9 +140,9 @@ public class MapReactorSessionRepository implements ReactorSessionRepository<Ses
|
||||
return Mono.fromRunnable(() -> this.sessions.remove(id));
|
||||
}
|
||||
|
||||
public Mono<Session> createSession() {
|
||||
public Mono<MapSession> createSession() {
|
||||
return Mono.defer(() -> {
|
||||
Session result = new MapSession();
|
||||
MapSession result = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
result.setMaxInactiveInterval(
|
||||
Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
|
||||
@@ -52,6 +52,7 @@ public final class MapSession implements Session, Serializable {
|
||||
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
|
||||
|
||||
private String id;
|
||||
private String originalId;
|
||||
private Map<String, Object> sessionAttrs = new HashMap<>();
|
||||
private Instant creationTime = Instant.now();
|
||||
private Instant lastAccessedTime = this.creationTime;
|
||||
@@ -65,9 +66,10 @@ public final class MapSession implements Session, Serializable {
|
||||
* Creates a new instance with a secure randomly generated identifier.
|
||||
*/
|
||||
public MapSession() {
|
||||
this(UUID.randomUUID().toString());
|
||||
this(generateId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -77,6 +79,7 @@ public final class MapSession implements Session, Serializable {
|
||||
*/
|
||||
public MapSession(String id) {
|
||||
this.id = id;
|
||||
this.originalId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +93,7 @@ public final class MapSession implements Session, Serializable {
|
||||
throw new IllegalArgumentException("session cannot be null");
|
||||
}
|
||||
this.id = session.getId();
|
||||
this.originalId = this.id;
|
||||
this.sessionAttrs = new HashMap<>(
|
||||
session.getAttributeNames().size());
|
||||
for (String attrName : session.getAttributeNames()) {
|
||||
@@ -115,6 +119,20 @@ public final class MapSession implements Session, Serializable {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
String getOriginalId() {
|
||||
return this.originalId;
|
||||
}
|
||||
|
||||
void setOriginalId(String originalId) {
|
||||
this.originalId = originalId;
|
||||
}
|
||||
|
||||
public String changeSessionId() {
|
||||
String changedId = generateId();
|
||||
setId(changedId);
|
||||
return changedId;
|
||||
}
|
||||
|
||||
public Instant getLastAccessedTime() {
|
||||
return this.lastAccessedTime;
|
||||
}
|
||||
@@ -188,5 +206,9 @@ public final class MapSession implements Session, Serializable {
|
||||
return this.id.hashCode();
|
||||
}
|
||||
|
||||
private static String generateId() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 7160779239673823561L;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.springframework.session.events.SessionExpiredEvent;
|
||||
* @author Rob Winch
|
||||
* @since 1.0
|
||||
*/
|
||||
public class MapSessionRepository implements SessionRepository<Session> {
|
||||
public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link Session#setMaxInactiveInterval(Duration)}.
|
||||
@@ -76,11 +76,15 @@ public class MapSessionRepository implements SessionRepository<Session> {
|
||||
this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval);
|
||||
}
|
||||
|
||||
public void save(Session session) {
|
||||
public void save(MapSession session) {
|
||||
if (!session.getId().equals(session.getOriginalId())) {
|
||||
this.sessions.remove(session.getOriginalId());
|
||||
session.setOriginalId(session.getId());
|
||||
}
|
||||
this.sessions.put(session.getId(), new MapSession(session));
|
||||
}
|
||||
|
||||
public Session findById(String id) {
|
||||
public MapSession findById(String id) {
|
||||
Session saved = this.sessions.get(id);
|
||||
if (saved == null) {
|
||||
return null;
|
||||
@@ -96,8 +100,8 @@ public class MapSessionRepository implements SessionRepository<Session> {
|
||||
this.sessions.remove(id);
|
||||
}
|
||||
|
||||
public Session createSession() {
|
||||
Session result = new MapSession();
|
||||
public MapSession createSession() {
|
||||
MapSession result = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
result.setMaxInactiveInterval(
|
||||
Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
|
||||
@@ -37,6 +37,12 @@ public interface Session {
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Changes the session id. After invoking the {@link #getId()} will return a new identifier.
|
||||
* @return the new session id which {@link #getId()} will now return
|
||||
*/
|
||||
String changeSessionId();
|
||||
|
||||
/**
|
||||
* Gets the Object associated with the specified name or null if no Object is
|
||||
* associated to that name.
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.springframework.session.web.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletContext;
|
||||
@@ -274,30 +271,7 @@ public class SessionRepositoryFilter<S extends Session>
|
||||
"Cannot change session ID. There is no session associated with this request.");
|
||||
}
|
||||
|
||||
// eagerly get session attributes in case implementation lazily loads them
|
||||
Map<String, Object> attrs = new HashMap<>();
|
||||
Enumeration<String> iAttrNames = session.getAttributeNames();
|
||||
while (iAttrNames.hasMoreElements()) {
|
||||
String attrName = iAttrNames.nextElement();
|
||||
Object value = session.getAttribute(attrName);
|
||||
|
||||
attrs.put(attrName, value);
|
||||
}
|
||||
|
||||
SessionRepositoryFilter.this.sessionRepository.deleteById(session.getId());
|
||||
HttpSessionWrapper original = getCurrentSession();
|
||||
setCurrentSession(null);
|
||||
|
||||
HttpSessionWrapper newSession = getSession();
|
||||
original.setSession(newSession.getSession());
|
||||
|
||||
newSession.setMaxInactiveInterval(session.getMaxInactiveInterval());
|
||||
for (Map.Entry<String, Object> attr : attrs.entrySet()) {
|
||||
String attrName = attr.getKey();
|
||||
Object attrValue = attr.getValue();
|
||||
newSession.setAttribute(attrName, attrValue);
|
||||
}
|
||||
return newSession.getId();
|
||||
return getCurrentSession().getSession().changeSessionId();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -145,4 +145,32 @@ public class MapReactorSessionRepositoryTests {
|
||||
assertThat(session.getMaxInactiveInterval())
|
||||
.isEqualTo(expectedMaxInterval);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeSessionIdWhenNotYetSaved() {
|
||||
MapSession createSession = this.repository.createSession().block();
|
||||
|
||||
String originalId = createSession.getId();
|
||||
createSession.changeSessionId();
|
||||
|
||||
this.repository.save(createSession).block();
|
||||
|
||||
assertThat(this.repository.findById(originalId).block()).isNull();
|
||||
assertThat(this.repository.findById(createSession.getId()).block()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeSessionIdWhenSaved() {
|
||||
MapSession createSession = this.repository.createSession().block();
|
||||
|
||||
this.repository.save(createSession).block();
|
||||
|
||||
String originalId = createSession.getId();
|
||||
createSession.changeSessionId();
|
||||
|
||||
this.repository.save(createSession).block();
|
||||
|
||||
assertThat(this.repository.findById(originalId).block()).isNull();
|
||||
assertThat(this.repository.findById(createSession.getId()).block()).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,4 +66,32 @@ public class MapSessionRepositoryTests {
|
||||
assertThat(session.getMaxInactiveInterval())
|
||||
.isEqualTo(expectedMaxInterval);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeSessionIdWhenNotYetSaved() {
|
||||
MapSession createSession = this.repository.createSession();
|
||||
|
||||
String originalId = createSession.getId();
|
||||
createSession.changeSessionId();
|
||||
|
||||
this.repository.save(createSession);
|
||||
|
||||
assertThat(this.repository.findById(originalId)).isNull();
|
||||
assertThat(this.repository.findById(createSession.getId())).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeSessionIdWhenSaved() {
|
||||
MapSession createSession = this.repository.createSession();
|
||||
|
||||
this.repository.save(createSession);
|
||||
|
||||
String originalId = createSession.getId();
|
||||
createSession.changeSessionId();
|
||||
|
||||
this.repository.save(createSession);
|
||||
|
||||
assertThat(this.repository.findById(originalId)).isNull();
|
||||
assertThat(this.repository.findById(createSession.getId())).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,10 @@ public class MapSessionTests {
|
||||
return Instant.EPOCH;
|
||||
}
|
||||
|
||||
public String changeSessionId() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return "id";
|
||||
}
|
||||
|
||||
@@ -76,9 +76,9 @@ public class SessionRepositoryFilterTests {
|
||||
|
||||
private Map<String, Session> sessions;
|
||||
|
||||
private SessionRepository<Session> sessionRepository;
|
||||
private SessionRepository<MapSession> sessionRepository;
|
||||
|
||||
private SessionRepositoryFilter<Session> filter;
|
||||
private SessionRepositoryFilter<MapSession> filter;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
@@ -422,7 +422,7 @@ public class SessionRepositoryFilterTests {
|
||||
public void doFilterSetsCookieIfChanged() throws Exception {
|
||||
this.sessionRepository = new MapSessionRepository() {
|
||||
@Override
|
||||
public Session findById(String id) {
|
||||
public MapSession findById(String id) {
|
||||
return createSession();
|
||||
}
|
||||
};
|
||||
@@ -1256,7 +1256,7 @@ public class SessionRepositoryFilterTests {
|
||||
@SuppressWarnings("unchecked")
|
||||
public void doFilterRequestSessionNoRequestSessionNoSessionRepositoryInteractions()
|
||||
throws Exception {
|
||||
SessionRepository<Session> sessionRepository = spy(new MapSessionRepository());
|
||||
SessionRepository<MapSession> sessionRepository = spy(new MapSessionRepository());
|
||||
|
||||
this.filter = new SessionRepositoryFilter<>(sessionRepository);
|
||||
|
||||
@@ -1283,7 +1283,7 @@ public class SessionRepositoryFilterTests {
|
||||
|
||||
@Test
|
||||
public void doFilterLazySessionCreation() throws Exception {
|
||||
SessionRepository<Session> sessionRepository = spy(new MapSessionRepository());
|
||||
SessionRepository<MapSession> sessionRepository = spy(new MapSessionRepository());
|
||||
|
||||
this.filter = new SessionRepositoryFilter<>(sessionRepository);
|
||||
|
||||
@@ -1299,9 +1299,9 @@ public class SessionRepositoryFilterTests {
|
||||
|
||||
@Test
|
||||
public void doFilterLazySessionUpdates() throws Exception {
|
||||
Session session = this.sessionRepository.createSession();
|
||||
MapSession session = this.sessionRepository.createSession();
|
||||
this.sessionRepository.save(session);
|
||||
SessionRepository<Session> sessionRepository = spy(this.sessionRepository);
|
||||
SessionRepository<MapSession> sessionRepository = spy(this.sessionRepository);
|
||||
setSessionCookie(session.getId());
|
||||
|
||||
this.filter = new SessionRepositoryFilter<>(sessionRepository);
|
||||
|
||||
Reference in New Issue
Block a user