001/* 002 * Copyright 2002-2020 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.server.session; 018 019import java.util.List; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023import reactor.core.publisher.Flux; 024import reactor.core.publisher.Mono; 025 026import org.springframework.util.Assert; 027import org.springframework.web.server.ServerWebExchange; 028import org.springframework.web.server.WebSession; 029 030/** 031 * Default implementation of {@link WebSessionManager} delegating to a 032 * {@link WebSessionIdResolver} for session id resolution and to a 033 * {@link WebSessionStore}. 034 * 035 * @author Rossen Stoyanchev 036 * @author Rob Winch 037 * @since 5.0 038 */ 039public class DefaultWebSessionManager implements WebSessionManager { 040 041 private static final Log logger = LogFactory.getLog(DefaultWebSessionManager.class); 042 043 044 private WebSessionIdResolver sessionIdResolver = new CookieWebSessionIdResolver(); 045 046 private WebSessionStore sessionStore = new InMemoryWebSessionStore(); 047 048 049 /** 050 * Configure the id resolution strategy. 051 * <p>By default an instance of {@link CookieWebSessionIdResolver}. 052 * @param sessionIdResolver the resolver to use 053 */ 054 public void setSessionIdResolver(WebSessionIdResolver sessionIdResolver) { 055 Assert.notNull(sessionIdResolver, "WebSessionIdResolver is required"); 056 this.sessionIdResolver = sessionIdResolver; 057 } 058 059 /** 060 * Return the configured {@link WebSessionIdResolver}. 061 */ 062 public WebSessionIdResolver getSessionIdResolver() { 063 return this.sessionIdResolver; 064 } 065 066 /** 067 * Configure the persistence strategy. 068 * <p>By default an instance of {@link InMemoryWebSessionStore}. 069 * @param sessionStore the persistence strategy to use 070 */ 071 public void setSessionStore(WebSessionStore sessionStore) { 072 Assert.notNull(sessionStore, "WebSessionStore is required"); 073 this.sessionStore = sessionStore; 074 } 075 076 /** 077 * Return the configured {@link WebSessionStore}. 078 */ 079 public WebSessionStore getSessionStore() { 080 return this.sessionStore; 081 } 082 083 084 @Override 085 public Mono<WebSession> getSession(ServerWebExchange exchange) { 086 return Mono.defer(() -> retrieveSession(exchange) 087 .switchIfEmpty(createWebSession()) 088 .doOnNext(session -> exchange.getResponse().beforeCommit(() -> save(exchange, session)))); 089 } 090 091 private Mono<WebSession> createWebSession() { 092 Mono<WebSession> session = this.sessionStore.createWebSession(); 093 if (logger.isDebugEnabled()) { 094 session = session.doOnNext(s -> logger.debug("Created new WebSession.")); 095 } 096 return session; 097 } 098 099 private Mono<WebSession> retrieveSession(ServerWebExchange exchange) { 100 return Flux.fromIterable(getSessionIdResolver().resolveSessionIds(exchange)) 101 .concatMap(this.sessionStore::retrieveSession) 102 .next(); 103 } 104 105 private Mono<Void> save(ServerWebExchange exchange, WebSession session) { 106 List<String> ids = getSessionIdResolver().resolveSessionIds(exchange); 107 108 if (!session.isStarted() || session.isExpired()) { 109 if (!ids.isEmpty()) { 110 // Expired on retrieve or while processing request, or invalidated.. 111 if (logger.isDebugEnabled()) { 112 logger.debug("WebSession expired or has been invalidated"); 113 } 114 this.sessionIdResolver.expireSession(exchange); 115 } 116 return Mono.empty(); 117 } 118 119 if (ids.isEmpty() || !session.getId().equals(ids.get(0))) { 120 this.sessionIdResolver.setSessionId(exchange, session.getId()); 121 } 122 123 return session.save(); 124 } 125 126}