Skip to content

Commit c6eaa05

Browse files
committed
WebSessionReactiveSecurityRepository Supports Cache
1 parent 7b6fd59 commit c6eaa05

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

web/src/main/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepository.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public class WebSessionServerSecurityContextRepository implements ServerSecurity
4646

4747
private String springSecurityContextAttrName = DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME;
4848

49+
private boolean cacheSecurityContext;
50+
4951
/**
5052
* Sets the session attribute name used to save and load the {@link SecurityContext}
5153
* @param springSecurityContextAttrName the session attribute name to use to save and
@@ -56,6 +58,16 @@ public void setSpringSecurityContextAttrName(String springSecurityContextAttrNam
5658
this.springSecurityContextAttrName = springSecurityContextAttrName;
5759
}
5860

61+
/**
62+
* If set to true the result of {@link #load(ServerWebExchange)} will use
63+
* {@link Mono#cache()} to prevent multiple lookups.
64+
* @param cacheSecurityContext true if {@link Mono#cache()} should be used, else
65+
* false.
66+
*/
67+
public void setCacheSecurityContext(boolean cacheSecurityContext) {
68+
this.cacheSecurityContext = cacheSecurityContext;
69+
}
70+
5971
@Override
6072
public Mono<Void> save(ServerWebExchange exchange, SecurityContext context) {
6173
return exchange.getSession().doOnNext((session) -> {
@@ -72,13 +84,14 @@ public Mono<Void> save(ServerWebExchange exchange, SecurityContext context) {
7284

7385
@Override
7486
public Mono<SecurityContext> load(ServerWebExchange exchange) {
75-
return exchange.getSession().flatMap((session) -> {
87+
Mono<SecurityContext> result = exchange.getSession().flatMap((session) -> {
7688
SecurityContext context = (SecurityContext) session.getAttribute(this.springSecurityContextAttrName);
7789
logger.debug((context != null)
7890
? LogMessage.format("Found SecurityContext '%s' in WebSession: '%s'", context, session)
7991
: LogMessage.format("No SecurityContext found in WebSession: '%s'", session));
8092
return Mono.justOrEmpty(context);
8193
});
94+
return (cacheSecurityContext) ? result.cache() : result;
8295
}
8396

8497
}

web/src/test/java/org/springframework/security/web/server/context/WebSessionServerSecurityContextRepositoryTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@
1717
package org.springframework.security.web.server.context;
1818

1919
import org.junit.jupiter.api.Test;
20+
import reactor.core.publisher.Mono;
21+
import reactor.test.publisher.PublisherProbe;
2022

2123
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
2224
import org.springframework.mock.web.server.MockServerWebExchange;
2325
import org.springframework.security.core.context.SecurityContext;
2426
import org.springframework.security.core.context.SecurityContextImpl;
27+
import org.springframework.web.server.ServerWebExchange;
2528
import org.springframework.web.server.WebSession;
2629

2730
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.mockito.BDDMockito.given;
32+
import static org.mockito.Mockito.mock;
2833

2934
/**
3035
* @author Rob Winch
@@ -79,4 +84,25 @@ public void loadWhenNullThenNull() {
7984
assertThat(context).isNull();
8085
}
8186

87+
@Test
88+
public void loadWhenCacheSecurityContextThenSubscribeOnce() {
89+
PublisherProbe<WebSession> webSession = PublisherProbe.empty();
90+
ServerWebExchange exchange = mock(ServerWebExchange.class);
91+
given(exchange.getSession()).willReturn(webSession.mono());
92+
this.repository.setCacheSecurityContext(true);
93+
Mono<SecurityContext> context = this.repository.load(exchange);
94+
assertThat(context.block()).isSameAs(context.block());
95+
assertThat(webSession.subscribeCount()).isEqualTo(1);
96+
}
97+
98+
@Test
99+
public void loadWhenNotCacheSecurityContextThenSubscribeMultiple() {
100+
PublisherProbe<WebSession> webSession = PublisherProbe.empty();
101+
ServerWebExchange exchange = mock(ServerWebExchange.class);
102+
given(exchange.getSession()).willReturn(webSession.mono());
103+
Mono<SecurityContext> context = this.repository.load(exchange);
104+
assertThat(context.block()).isSameAs(context.block());
105+
assertThat(webSession.subscribeCount()).isEqualTo(2);
106+
}
107+
82108
}

0 commit comments

Comments
 (0)