使用 spring-security 和 spring-webflux 时禁用 WebSession 创建
Disable WebSession creation when using spring-security with spring-webflux
我是 运行 一个无状态 spring-boot 应用程序,有一个休息 api 并且想要禁用 WebSessions 的创建,如所述 https://www.baeldung.com/spring-security-session
我创建了自己的不存储会话的 WebSessionManager。
@Bean
public WebSessionManager webSessionManager() {
return new WebSessionManager() {
@Override
@NonNull
public Mono<WebSession> getSession(@NonNull final ServerWebExchange exchange) {
return Mono.just(new WebSession() {
@Override
@NonNull
public String getId() {
return "";
}
@Override
@NonNull
public Map<String, Object> getAttributes() {
return new HashMap<>();
}
@Override
public void start() {
}
@Override
public boolean isStarted() {
return true;
}
@Override
@NonNull
public Mono<Void> changeSessionId() {
return Mono.empty();
}
@Override
@NonNull
public Mono<Void> invalidate() {
return Mono.empty();
}
@Override
@NonNull
public Mono<Void> save() {
return Mono.empty();
}
@Override
public boolean isExpired() {
return false;
}
@Override
@NonNull
public Instant getCreationTime() {
return Instant.now();
}
@Override
@NonNull
public Instant getLastAccessTime() {
return Instant.now();
}
@Override
public void setMaxIdleTime(@NonNull final Duration maxIdleTime) {
}
@Override
@NonNull
public Duration getMaxIdleTime() {
return Duration.ofMinutes(1);
}
});
}
};
}
它有效,但我想知道是否有更好的方法来不创建会话。
Issue #6552: Session Creation Policy with Webflux Security 将由 Spring 团队修复。
The problem is that the request cache is being invoked for every request to see if there is a value saved to replay and thus the WebSession is being looked up for every request. Since the WebSession is being looked up with an invalid session id, Spring WebFlux invalidates the SESSION cookie. ~ rwinch
DarrenJiang1990建议的解决方案是:
.and().securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
The security context in a WebFlux application is stored in a ServerSecurityContextRepository. Its WebSessionServerSecurityContextRepository implementation, which is used by default, stores the context in session. Configuring a NoOpServerSecurityContextRepository instead would make our application stateless
您可以在Issue #7157 ServerRequestCacheWebFilter causes WebSession to be read every request中跟踪补丁进度。
使用:用于此目的的 NoOpServerSecurityContextRepository。
@Configuration
@EnableWebFluxSecurity
@ComponentScan(value = {"my.package.security"})
public class SpringSecurityConfig2 {
@Autowired private MyHeaderExchangeMatcher myHeaderExchangeMatcher;
@Autowired private MyReactiveAuthenticationManager myReactiveAuthenticationManager;
@Autowired private MyTokenAuthenticationConverter myTokenAuthenticationConverter;
@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
http.httpBasic().disable().formLogin().disable().csrf().disable().logout().disable();
http...
.addFilterAt(webFilter(), SecurityWebFiltersOrder.AUTHORIZATION)
...;
return http.build();
}
@Bean
public AuthenticationWebFilter webFilter() {
AuthenticationWebFilter authenticationWebFilter =
new AuthenticationWebFilter(myReactiveAuthenticationManager);
authenticationWebFilter.setServerAuthenticationConverter(myTokenAuthenticationConverter);
authenticationWebFilter.setRequiresAuthenticationMatcher(myHeaderExchangeMatcher);
// NoOpServerSecurityContextRepository is used to for stateless sessions so no session or state is persisted between requests.
// The client must send the Authorization header with every request.
NoOpServerSecurityContextRepository sessionConfig = NoOpServerSecurityContextRepository.getInstance();
authenticationWebFilter.setSecurityContextRepository(sessionConfig);
return authenticationWebFilter;
}
}
我已经通过以下技巧禁用了 WebSessionManager
@Bean
public WebSessionManager webSessionManager() {
// Emulate SessionCreationPolicy.STATELESS
return exchange -> Mono.empty();
}
所有其他解决方案对我都没有帮助。
我是 运行 一个无状态 spring-boot 应用程序,有一个休息 api 并且想要禁用 WebSessions 的创建,如所述 https://www.baeldung.com/spring-security-session
我创建了自己的不存储会话的 WebSessionManager。
@Bean
public WebSessionManager webSessionManager() {
return new WebSessionManager() {
@Override
@NonNull
public Mono<WebSession> getSession(@NonNull final ServerWebExchange exchange) {
return Mono.just(new WebSession() {
@Override
@NonNull
public String getId() {
return "";
}
@Override
@NonNull
public Map<String, Object> getAttributes() {
return new HashMap<>();
}
@Override
public void start() {
}
@Override
public boolean isStarted() {
return true;
}
@Override
@NonNull
public Mono<Void> changeSessionId() {
return Mono.empty();
}
@Override
@NonNull
public Mono<Void> invalidate() {
return Mono.empty();
}
@Override
@NonNull
public Mono<Void> save() {
return Mono.empty();
}
@Override
public boolean isExpired() {
return false;
}
@Override
@NonNull
public Instant getCreationTime() {
return Instant.now();
}
@Override
@NonNull
public Instant getLastAccessTime() {
return Instant.now();
}
@Override
public void setMaxIdleTime(@NonNull final Duration maxIdleTime) {
}
@Override
@NonNull
public Duration getMaxIdleTime() {
return Duration.ofMinutes(1);
}
});
}
};
}
它有效,但我想知道是否有更好的方法来不创建会话。
Issue #6552: Session Creation Policy with Webflux Security 将由 Spring 团队修复。
The problem is that the request cache is being invoked for every request to see if there is a value saved to replay and thus the WebSession is being looked up for every request. Since the WebSession is being looked up with an invalid session id, Spring WebFlux invalidates the SESSION cookie. ~ rwinch
DarrenJiang1990建议的解决方案是:
.and().securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
The security context in a WebFlux application is stored in a ServerSecurityContextRepository. Its WebSessionServerSecurityContextRepository implementation, which is used by default, stores the context in session. Configuring a NoOpServerSecurityContextRepository instead would make our application stateless
您可以在Issue #7157 ServerRequestCacheWebFilter causes WebSession to be read every request中跟踪补丁进度。
使用:用于此目的的 NoOpServerSecurityContextRepository。
@Configuration
@EnableWebFluxSecurity
@ComponentScan(value = {"my.package.security"})
public class SpringSecurityConfig2 {
@Autowired private MyHeaderExchangeMatcher myHeaderExchangeMatcher;
@Autowired private MyReactiveAuthenticationManager myReactiveAuthenticationManager;
@Autowired private MyTokenAuthenticationConverter myTokenAuthenticationConverter;
@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
http.httpBasic().disable().formLogin().disable().csrf().disable().logout().disable();
http...
.addFilterAt(webFilter(), SecurityWebFiltersOrder.AUTHORIZATION)
...;
return http.build();
}
@Bean
public AuthenticationWebFilter webFilter() {
AuthenticationWebFilter authenticationWebFilter =
new AuthenticationWebFilter(myReactiveAuthenticationManager);
authenticationWebFilter.setServerAuthenticationConverter(myTokenAuthenticationConverter);
authenticationWebFilter.setRequiresAuthenticationMatcher(myHeaderExchangeMatcher);
// NoOpServerSecurityContextRepository is used to for stateless sessions so no session or state is persisted between requests.
// The client must send the Authorization header with every request.
NoOpServerSecurityContextRepository sessionConfig = NoOpServerSecurityContextRepository.getInstance();
authenticationWebFilter.setSecurityContextRepository(sessionConfig);
return authenticationWebFilter;
}
}
我已经通过以下技巧禁用了 WebSessionManager
@Bean
public WebSessionManager webSessionManager() {
// Emulate SessionCreationPolicy.STATELESS
return exchange -> Mono.empty();
}
所有其他解决方案对我都没有帮助。