将 spring-security 与 spring-webflux 一起使用时禁用 WebSession 创建
Posted
技术标签:
【中文标题】将 spring-security 与 spring-webflux 一起使用时禁用 WebSession 创建【英文标题】:Disable WebSession creation when using spring-security with spring-webflux 【发布时间】:2019-09-27 02:41:08 【问题描述】:我正在运行一个带有 rest api 的无状态 spring-boot 应用程序,并希望按照https://www.baeldung.com/spring-security-session 的描述禁用 WebSessions 的创建
我创建了自己的不存储会话的 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);
);
;
它有效,但我想知道是否有更好的方法来不创建会话。
【问题讨论】:
【参考方案1】:Issue #6552: Session Creation Policy with Webflux Security 将由 Spring 团队修复。
问题是每个请求都会调用请求缓存,以查看是否有保存的值要重播,因此正在为每个请求查找 WebSession。由于使用无效会话 id 查找 WebSession,因此 Spring WebFlux 使 SESSION cookie 无效。 ~rwinch
我创建了 gh-7157 来限制何时访问请求缓存(以及 WebSession)。同时,如果您不需要请求缓存,可以使用以下命令禁用它:
http
.requestCache()
.requestCache(NoOpServerRequestCache.getInstance());
您可以在Issue #7157 ServerRequestCacheWebFilter causes WebSession to be read every request 中跟踪修补进度。
另外DarrenJiang1990 建议更完整的解决方案:
.and().securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
WebFlux 应用程序中的安全上下文存储在 ServerSecurityContextRepository 中。其默认使用的 WebSessionServerSecurityContextRepository 实现将上下文存储在会话中。配置 NoOpServerSecurityContextRepository 将使我们的应用程序无状态
(以前的解决方法)
除了覆盖WebSessionManager
,您还可以禁用所有安全功能,并用您的自定义实现替换authenticationManager
和securityContextRepository
,去除基于会话的功能:
@Configuration
public class SecurityConfiguration
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http)
// Disable default security.
http.httpBasic().disable();
http.formLogin().disable();
http.csrf().disable();
http.logout().disable();
// Add custom security.
http.authenticationManager(this.authenticationManager);
http.securityContextRepository(this.securityContextRepository);
// Disable authentication for `/auth/**` routes.
http.authorizeExchange().pathMatchers("/auth/**").permitAll();
http.authorizeExchange().anyExchange().authenticated();
return http.build();
更多信息:Spring webflux custom authentication for API 。
【讨论】:
感谢您的回复!不过,SecurityWebFilterChain 无法解决创建网络会话的问题。 我已经在 Github 问题上写了关于这个 SO 问题的评论,希望他们能尽快将.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
修补到 WebFlux 中。
Spring 团队正在努力解决这个问题。我已经用建议的解决方法更新了答案。【参考方案2】:
我通过以下技巧禁用了 WebSessionManager
@Bean
public WebSessionManager webSessionManager()
// Emulate SessionCreationPolicy.STATELESS
return exchange -> Mono.empty();
所有其他解决方案都对我没有帮助。
【讨论】:
【参考方案3】:使用: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;
【讨论】:
【参考方案4】:你试过了吗:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
?
【讨论】:
这个应用程序使用的是 spring-webflux 所以我们没有 HttpSecurity 而是 ServerHttpSecurity 所以它没有工作。 我的错,我打开了多个项目,我确信这是可行的解决方案!我和 spring-webflux 的家伙有点来回折腾,他们有很多关于处理和安全的正在进行的项目......以上是关于将 spring-security 与 spring-webflux 一起使用时禁用 WebSession 创建的主要内容,如果未能解决你的问题,请参考以下文章
将标头添加到 oauth/token 响应(spring-security)
您如何在代理后面使用 spring-security OAuth2,但仅将 ForwardedHeaderTransformer 用于 OAuth 组件