Add WebSession.invalidate()

Issue: SPR-15960
This commit is contained in:
Rossen Stoyanchev
2017-09-27 00:10:38 -04:00
parent 6da3518a66
commit 15cc44e6e8
6 changed files with 77 additions and 27 deletions

View File

@@ -109,6 +109,12 @@ public interface WebSession {
*/
Mono<Void> changeSessionId();
/**
* Invalidate the current session and clear session storage.
* @return completion notification (success or error)
*/
Mono<Void> invalidate();
/**
* Save the session persisting attributes (e.g. if stored remotely) and also
* sending the session id to the client if the session is new.

View File

@@ -90,26 +90,21 @@ public class DefaultWebSessionManager implements WebSessionManager {
}
private Mono<Void> save(ServerWebExchange exchange, WebSession session) {
if (session.isExpired()) {
return Mono.error(new IllegalStateException("Session='" + session.getId() + "' expired."));
}
if (!session.isStarted()) {
if (hasNewSessionId(exchange, session)) {
List<String> ids = getSessionIdResolver().resolveSessionIds(exchange);
if (!session.isStarted() || session.isExpired()) {
if (!ids.isEmpty()) {
// Expired on retrieve or while processing request, or invalidated..
this.sessionIdResolver.expireSession(exchange);
}
return Mono.empty();
}
if (hasNewSessionId(exchange, session)) {
if (ids.isEmpty() || !session.getId().equals(ids.get(0))) {
this.sessionIdResolver.setSessionId(exchange, session.getId());
}
return session.save();
}
private boolean hasNewSessionId(ServerWebExchange exchange, WebSession session) {
List<String> ids = getSessionIdResolver().resolveSessionIds(exchange);
return ids.isEmpty() || !session.getId().equals(ids.get(0));
}
}

View File

@@ -109,25 +109,22 @@ public class InMemoryWebSessionStore implements WebSessionStore {
private class InMemoryWebSession implements WebSession {
private final AtomicReference<String> id;
private final AtomicReference<String> id = new AtomicReference<>(String.valueOf(idGenerator.generateId()));
private final Map<String, Object> attributes;
private final Map<String, Object> attributes = new ConcurrentHashMap<>();
private final Instant creationTime;
private volatile Instant lastAccessTime;
private volatile Duration maxIdleTime;
private volatile Duration maxIdleTime = Duration.ofMinutes(30);
private volatile boolean started;
private final AtomicReference<State> state = new AtomicReference<>(State.NEW);
InMemoryWebSession() {
this.id = new AtomicReference<>(String.valueOf(idGenerator.generateId()));
this.attributes = new ConcurrentHashMap<>();
this.creationTime = Instant.now(getClock());
this.lastAccessTime = this.creationTime;
this.maxIdleTime = Duration.ofMinutes(30);
}
@@ -163,12 +160,12 @@ public class InMemoryWebSessionStore implements WebSessionStore {
@Override
public void start() {
this.started = true;
this.state.compareAndSet(State.NEW, State.STARTED);
}
@Override
public boolean isStarted() {
return this.started || !getAttributes().isEmpty();
return this.state.get().equals(State.STARTED) || !getAttributes().isEmpty();
}
@Override
@@ -185,21 +182,46 @@ public class InMemoryWebSessionStore implements WebSessionStore {
return Mono.empty();
}
@Override
public Mono<Void> invalidate() {
this.state.set(State.EXPIRED);
getAttributes().clear();
InMemoryWebSessionStore.this.sessions.remove(this.id.get());
return Mono.empty();
}
@Override
public Mono<Void> save() {
if (!getAttributes().isEmpty()) {
this.state.compareAndSet(State.NEW, State.STARTED);
}
InMemoryWebSessionStore.this.sessions.put(this.getId(), this);
return Mono.empty();
}
@Override
public boolean isExpired() {
return (isStarted() && !this.maxIdleTime.isNegative() &&
Instant.now(getClock()).minus(this.maxIdleTime).isAfter(this.lastAccessTime));
if (this.state.get().equals(State.EXPIRED)) {
return true;
}
if (checkExpired()) {
this.state.set(State.EXPIRED);
return true;
}
return false;
}
private boolean checkExpired() {
return isStarted() && !this.maxIdleTime.isNegative() &&
Instant.now(getClock()).minus(this.maxIdleTime).isAfter(this.lastAccessTime);
}
private void updateLastAccessTime() {
this.lastAccessTime = Instant.now(getClock());
}
}
private enum State { NEW, STARTED, EXPIRED }
}