Java 将spring security与spring webflux一起使用时禁用WebSession创建

Java 将spring security与spring webflux一起使用时禁用WebSession创建,java,spring-security,spring-webflux,Java,Spring Security,Spring Webflux,我正在运行一个带有RESTAPI的无状态spring引导应用程序,并希望禁用WebSessions的创建,如前所述 我创建了自己的WebSessionManager,它不存储会话 @Bean public WebSessionManager webSessionManager() { return new WebSessionManager() { @Override @NonNull public Mo

我正在运行一个带有RESTAPI的无状态spring引导应用程序,并希望禁用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);
                   }
               });
           }
       };
   }
它可以工作,但我想知道是否有更好的方法不创建会话。

您尝试过:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}

这个问题将由Spring团队解决

问题在于,每个请求都会调用请求缓存,以查看是否保存了要重播的值,因此每个请求都会查找WebSession。由于正在使用无效会话id查找WebSession,因此Spring WebFlux会使会话cookie无效

我创建了gh-7157来限制何时访问请求缓存,从而限制WebSession。同时,如果您不需要请求缓存,可以使用以下方法禁用它:

您可以在中跟踪修补的进度

此外,还建议更完整的解决方案:

.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();
    }
}

更多信息:.

使用用于此目的的: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 webflux,因此我们没有HttpSecurity,而是ServerHttpSecurity,因此它不起作用。糟糕的是,我打开了多个项目,我确信这是有效的解决方案!我和SpringWebFlux的家伙们有点来往,他们有很多关于处理和安全的正在进行的项目…谢谢你的回复!虽然SecurityWebFilterChain无法解决创建Web会话的问题。我已经就Github问题就这个问题发表了评论,希望他们能很快将.sessionCreationPolicySessionCreationPolicy.STATELESS修补到WebFlux中。Spring团队正在修复这个问题。我已经用建议的解决方法更新了答案。
  @Bean
  public WebSessionManager webSessionManager() {
    // Emulate SessionCreationPolicy.STATELESS
    return exchange -> Mono.empty();
  }