Skip to content

Commit 3c71637

Browse files
committed
Polish 'Add more session properties for reactive web servers'
See gh-26714
1 parent a2a802a commit 3c71637

File tree

7 files changed

+81
-93
lines changed

7 files changed

+81
-93
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoReactiveSessionConfiguration.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
* Mongo-backed reactive session configuration.
3636
*
3737
* @author Andy Wilkinson
38+
* @author Weix Sun
3839
*/
3940
@Configuration(proxyBeanMethods = false)
4041
@ConditionalOnClass({ ReactiveMongoOperations.class, ReactiveMongoSessionRepository.class })

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisReactiveSessionConfiguration.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
* Redis-backed reactive session configuration.
3636
*
3737
* @author Andy Wilkinson
38+
* @author Weix Sun
3839
*/
3940
@Configuration(proxyBeanMethods = false)
4041
@ConditionalOnClass({ ReactiveRedisConnectionFactory.class, ReactiveRedisSessionRepository.class })

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.autoconfigure.session;
1818

19+
import java.time.Duration;
1920
import java.util.ArrayList;
2021
import java.util.Arrays;
2122
import java.util.List;
@@ -31,7 +32,6 @@
3132
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3233
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3334
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
34-
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
3535
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
3636
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
3737
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
@@ -56,6 +56,7 @@
5656
import org.springframework.context.annotation.Import;
5757
import org.springframework.context.annotation.ImportSelector;
5858
import org.springframework.core.type.AnnotationMetadata;
59+
import org.springframework.http.ResponseCookie.ResponseCookieBuilder;
5960
import org.springframework.security.web.authentication.RememberMeServices;
6061
import org.springframework.session.ReactiveSessionRepository;
6162
import org.springframework.session.Session;
@@ -65,6 +66,7 @@
6566
import org.springframework.session.web.http.CookieSerializer;
6667
import org.springframework.session.web.http.DefaultCookieSerializer;
6768
import org.springframework.session.web.http.HttpSessionIdResolver;
69+
import org.springframework.util.StringUtils;
6870
import org.springframework.web.server.session.CookieWebSessionIdResolver;
6971
import org.springframework.web.server.session.WebSessionIdResolver;
7072

@@ -106,7 +108,7 @@ DefaultCookieSerializer cookieSerializer(ServerProperties serverProperties,
106108
map.from(cookie::getPath).to(cookieSerializer::setCookiePath);
107109
map.from(cookie::getHttpOnly).to(cookieSerializer::setUseHttpOnlyCookie);
108110
map.from(cookie::getSecure).to(cookieSerializer::setUseSecureCookie);
109-
map.from(cookie::getMaxAge).to((maxAge) -> cookieSerializer.setCookieMaxAge((int) maxAge.getSeconds()));
111+
map.from(cookie::getMaxAge).asInt(Duration::getSeconds).to(cookieSerializer::setCookieMaxAge);
110112
cookieSerializerCustomizers.orderedStream().forEach((customizer) -> customizer.customize(cookieSerializer));
111113
return cookieSerializer;
112114
}
@@ -138,27 +140,34 @@ static class ServletSessionRepositoryConfiguration {
138140
@Import(ReactiveSessionRepositoryValidator.class)
139141
static class ReactiveSessionConfiguration {
140142

141-
private static final String WEB_SESSION_ID_RESOLVER_BEAN_NAME = "webSessionIdResolver";
143+
private final WebFluxProperties webFluxProperties;
144+
145+
ReactiveSessionConfiguration(WebFluxProperties webFluxProperties) {
146+
this.webFluxProperties = webFluxProperties;
147+
}
142148

143149
@Bean
144-
@ConditionalOnMissingClass(WEB_SESSION_ID_RESOLVER_BEAN_NAME)
145-
WebSessionIdResolver webSessionIdResolver(WebFluxProperties webFluxProperties) {
146-
final WebFluxProperties.Cookie cookie = webFluxProperties.getSession().getCookie();
150+
@ConditionalOnMissingBean
151+
WebSessionIdResolver webSessionIdResolver() {
152+
WebFluxProperties.Cookie cookieProperties = this.webFluxProperties.getSession().getCookie();
147153
CookieWebSessionIdResolver webSessionIdResolver = new CookieWebSessionIdResolver();
148-
webSessionIdResolver.setCookieName(cookie.getName());
149-
webSessionIdResolver.setCookieMaxAge(cookie.getMaxAge());
150-
webSessionIdResolver.addCookieInitializer((cookieBuilder) -> applyOtherProperties(cookie, cookieBuilder));
154+
String cookieName = cookieProperties.getName();
155+
if (StringUtils.hasText(cookieName)) {
156+
webSessionIdResolver.setCookieName(cookieName);
157+
}
158+
webSessionIdResolver.addCookieInitializer(this::initializeCookie);
151159
return webSessionIdResolver;
152160
}
153161

154-
private void applyOtherProperties(WebFluxProperties.Cookie cookie,
155-
org.springframework.http.ResponseCookie.ResponseCookieBuilder cookieBuilder) {
162+
private void initializeCookie(ResponseCookieBuilder builder) {
163+
WebFluxProperties.Cookie cookie = this.webFluxProperties.getSession().getCookie();
156164
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
157-
map.from(cookie::getDomain).to(cookieBuilder::domain);
158-
map.from(cookie::getPath).to(cookieBuilder::path);
159-
map.from(cookie::getHttpOnly).to(cookieBuilder::httpOnly);
160-
map.from(cookie::getSecure).to(cookieBuilder::secure);
161-
map.from(cookie::getSameSite).as(SameSite::attribute).to(cookieBuilder::sameSite);
165+
map.from(cookie::getDomain).to(builder::domain);
166+
map.from(cookie::getPath).to(builder::path);
167+
map.from(cookie::getHttpOnly).to(builder::httpOnly);
168+
map.from(cookie::getSecure).to(builder::secure);
169+
map.from(cookie::getMaxAge).to(builder::maxAge);
170+
map.from(cookie::getSameSite).as(SameSite::attribute).to(builder::sameSite);
162171
}
163172

164173
@Configuration(proxyBeanMethods = false)

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@
5757
import org.springframework.core.annotation.Order;
5858
import org.springframework.format.FormatterRegistry;
5959
import org.springframework.format.support.FormattingConversionService;
60+
import org.springframework.http.ResponseCookie.ResponseCookieBuilder;
6061
import org.springframework.http.codec.ServerCodecConfigurer;
6162
import org.springframework.util.ClassUtils;
63+
import org.springframework.util.StringUtils;
6264
import org.springframework.validation.Validator;
6365
import org.springframework.web.filter.reactive.HiddenHttpMethodFilter;
6466
import org.springframework.web.reactive.config.DelegatingWebFluxConfiguration;
@@ -311,47 +313,50 @@ public LocaleContextResolver localeContextResolver() {
311313
@ConditionalOnMissingBean(name = WebHttpHandlerBuilder.WEB_SESSION_MANAGER_BEAN_NAME)
312314
public WebSessionManager webSessionManager(ObjectProvider<WebSessionIdResolver> webSessionIdResolver) {
313315
DefaultWebSessionManager webSessionManager = new DefaultWebSessionManager();
314-
DefaultInMemoryWebSessionStore sessionStore = new DefaultInMemoryWebSessionStore(
315-
this.webFluxProperties.getSession().getTimeout());
316-
webSessionManager.setSessionStore(sessionStore);
316+
Duration timeout = this.webFluxProperties.getSession().getTimeout();
317+
webSessionManager.setSessionStore(new MaxIdleTimeInMemoryWebSessionStore(timeout));
317318
webSessionManager.setSessionIdResolver(webSessionIdResolver.getIfAvailable(cookieWebSessionIdResolver()));
318319
return webSessionManager;
319320
}
320321

321322
private Supplier<WebSessionIdResolver> cookieWebSessionIdResolver() {
322323
return () -> {
323-
CookieWebSessionIdResolver webSessionIdResolver = new CookieWebSessionIdResolver();
324-
webSessionIdResolver.setCookieName(this.webFluxProperties.getSession().getCookie().getName());
325-
webSessionIdResolver.addCookieInitializer((cookie) -> applyOtherProperties(cookie));
326-
return webSessionIdResolver;
324+
CookieWebSessionIdResolver resolver = new CookieWebSessionIdResolver();
325+
String cookieName = this.webFluxProperties.getSession().getCookie().getName();
326+
if (StringUtils.hasText(cookieName)) {
327+
resolver.setCookieName(cookieName);
328+
}
329+
resolver.addCookieInitializer(this::initializeCookie);
330+
return resolver;
327331
};
328332
}
329333

330-
private void applyOtherProperties(org.springframework.http.ResponseCookie.ResponseCookieBuilder cookieBuilder) {
334+
private void initializeCookie(ResponseCookieBuilder builder) {
331335
Cookie cookie = this.webFluxProperties.getSession().getCookie();
332336
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
333-
map.from(cookie::getDomain).to(cookieBuilder::domain);
334-
map.from(cookie::getPath).to(cookieBuilder::path);
335-
map.from(cookie::getMaxAge).to(cookieBuilder::maxAge);
336-
map.from(cookie::getHttpOnly).to(cookieBuilder::httpOnly);
337-
map.from(cookie::getSecure).to(cookieBuilder::secure);
338-
map.from(cookie::getSameSite).as(SameSite::attribute).to(cookieBuilder::sameSite);
337+
map.from(cookie::getDomain).to(builder::domain);
338+
map.from(cookie::getPath).to(builder::path);
339+
map.from(cookie::getHttpOnly).to(builder::httpOnly);
340+
map.from(cookie::getSecure).to(builder::secure);
341+
map.from(cookie::getMaxAge).to(builder::maxAge);
342+
map.from(cookie::getSameSite).as(SameSite::attribute).to(builder::sameSite);
339343
}
340344

341-
static final class DefaultInMemoryWebSessionStore extends InMemoryWebSessionStore {
345+
static final class MaxIdleTimeInMemoryWebSessionStore extends InMemoryWebSessionStore {
342346

343347
private final Duration timeout;
344348

345-
private DefaultInMemoryWebSessionStore(Duration timeout) {
349+
private MaxIdleTimeInMemoryWebSessionStore(Duration timeout) {
346350
this.timeout = timeout;
347351
}
348352

349353
@Override
350354
public Mono<WebSession> createWebSession() {
351-
return super.createWebSession().flatMap((inMemoryWebSession) -> {
352-
inMemoryWebSession.setMaxIdleTime(this.timeout);
353-
return Mono.just(inMemoryWebSession);
354-
});
355+
return super.createWebSession().doOnSuccess(this::setMaxIdleTime);
356+
}
357+
358+
private void setMaxIdleTime(WebSession session) {
359+
session.setMaxIdleTime(this.timeout);
355360
}
356361

357362
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxProperties.java

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,6 @@ public static class Session {
136136

137137
private final Cookie cookie = new Cookie();
138138

139-
public Cookie getCookie() {
140-
return this.cookie;
141-
}
142-
143139
public Duration getTimeout() {
144140
return this.timeout;
145141
}
@@ -148,16 +144,18 @@ public void setTimeout(Duration timeout) {
148144
this.timeout = timeout;
149145
}
150146

147+
public Cookie getCookie() {
148+
return this.cookie;
149+
}
150+
151151
}
152152

153153
public static class Cookie {
154154

155-
private static final String COOKIE_NAME = "SESSION";
156-
157155
/**
158156
* Name attribute value for session Cookies.
159157
*/
160-
private String name = COOKIE_NAME;
158+
private String name;
161159

162160
/**
163161
* Domain attribute value for session Cookies.
@@ -169,35 +167,31 @@ public static class Cookie {
169167
*/
170168
private String path;
171169

172-
/**
173-
* Maximum age of the session cookie. If a duration suffix is not specified,
174-
* seconds will be used. A positive value indicates when the cookie expires
175-
* relative to the current time. A value of 0 means the cookie should expire
176-
* immediately. A negative value means no "Max-Age" attribute in which case the
177-
* cookie is removed when the browser is closed.
178-
*/
179-
@DurationUnit(ChronoUnit.SECONDS)
180-
private Duration maxAge = Duration.ofSeconds(-1);
181-
182170
/**
183171
* HttpOnly attribute value for session Cookies.
184172
*/
185-
private Boolean httpOnly = true;
173+
private Boolean httpOnly;
186174

187175
/**
188176
* Secure attribute value for session Cookies.
189177
*/
190178
private Boolean secure;
191179

192180
/**
193-
* SameSite attribute value for session Cookies.
181+
* Maximum age of the session cookie. If a duration suffix is not specified,
182+
* seconds will be used. A positive value indicates when the cookie expires
183+
* relative to the current time. A value of 0 means the cookie should expire
184+
* immediately. A negative value means no "Max-Age" attribute in which case the
185+
* cookie is removed when the browser is closed.
194186
*/
195-
private SameSite sameSite = SameSite.LAX;
187+
@DurationUnit(ChronoUnit.SECONDS)
188+
private Duration maxAge;
196189

197190
/**
198-
* Return the session cookie name.
199-
* @return the session cookie name
191+
* SameSite attribute value for session Cookies.
200192
*/
193+
private SameSite sameSite;
194+
201195
public String getName() {
202196
return this.name;
203197
}
@@ -206,10 +200,6 @@ public void setName(String name) {
206200
this.name = name;
207201
}
208202

209-
/**
210-
* Return the domain for the session cookie.
211-
* @return the session cookie domain
212-
*/
213203
public String getDomain() {
214204
return this.domain;
215205
}
@@ -218,10 +208,6 @@ public void setDomain(String domain) {
218208
this.domain = domain;
219209
}
220210

221-
/**
222-
* Return the path of the session cookie.
223-
* @return the session cookie path
224-
*/
225211
public String getPath() {
226212
return this.path;
227213
}
@@ -230,22 +216,6 @@ public void setPath(String path) {
230216
this.path = path;
231217
}
232218

233-
/**
234-
* Return the maximum age of the session cookie.
235-
* @return the maximum age of the session cookie
236-
*/
237-
public Duration getMaxAge() {
238-
return this.maxAge;
239-
}
240-
241-
public void setMaxAge(Duration maxAge) {
242-
this.maxAge = maxAge;
243-
}
244-
245-
/**
246-
* Return whether to use "HttpOnly" cookies for session cookies.
247-
* @return {@code true} to use "HttpOnly" cookies for session cookies.
248-
*/
249219
public Boolean getHttpOnly() {
250220
return this.httpOnly;
251221
}
@@ -254,11 +224,6 @@ public void setHttpOnly(Boolean httpOnly) {
254224
this.httpOnly = httpOnly;
255225
}
256226

257-
/**
258-
* Return whether to always mark the session cookie as secure.
259-
* @return {@code true} to mark the session cookie as secure even if the request
260-
* that initiated the corresponding session is using plain HTTP
261-
*/
262227
public Boolean getSecure() {
263228
return this.secure;
264229
}
@@ -267,6 +232,14 @@ public void setSecure(Boolean secure) {
267232
this.secure = secure;
268233
}
269234

235+
public Duration getMaxAge() {
236+
return this.maxAge;
237+
}
238+
239+
public void setMaxAge(Duration maxAge) {
240+
this.maxAge = maxAge;
241+
}
242+
270243
public SameSite getSameSite() {
271244
return this.sameSite;
272245
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizerTests.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ void customizeSessionProperties() {
122122
assertThat(cookie.getComment()).isEqualTo("testcomment");
123123
assertThat(cookie.getHttpOnly()).isTrue();
124124
assertThat(cookie.getMaxAge()).hasSeconds(60);
125-
126125
}
127126

128127
@Test

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Session.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -47,10 +47,6 @@ public class Session {
4747

4848
private final SessionStoreDirectory sessionStoreDirectory = new SessionStoreDirectory();
4949

50-
public Cookie getCookie() {
51-
return this.cookie;
52-
}
53-
5450
public Duration getTimeout() {
5551
return this.timeout;
5652
}
@@ -96,6 +92,10 @@ public void setStoreDir(File storeDir) {
9692
this.storeDir = storeDir;
9793
}
9894

95+
public Cookie getCookie() {
96+
return this.cookie;
97+
}
98+
9999
SessionStoreDirectory getSessionStoreDirectory() {
100100
return this.sessionStoreDirectory;
101101
}

0 commit comments

Comments
 (0)