使用 spring-security 和 spring-webflux 时禁用 WebSession 创建

lin*_*bon 2 java spring-security spring-webflux

我正在运行一个带有 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);
                   }
               });
           }
       };
   }
Run Code Online (Sandbox Code Playgroud)

它有效,但我想知道是否有更好的方法来不创建会话。

Xar*_*lus 6

问题#6552:与Webflux安全会话创建策略将是由Spring团队来固定。

问题是每个请求都会调用请求缓存,以查看是否有保存的值可以重播,因此每个请求都会查找 WebSession。由于正在使用无效的会话 ID 查找 WebSession,因此 Spring WebFlux 使 SESSION cookie 无效。~绞盘

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

http
.requestCache()
    .requestCache(NoOpServerRequestCache.getInstance());
Run Code Online (Sandbox Code Playgroud)

您可以在问题 #7157 ServerRequestCacheWebFilter 中跟踪修补进度,导致每个请求都读取 WebSession

另外DarrenJiang1990建议更完整的解决方案:

.and().securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

更多信息:API 的 Spring webflux 自定义身份验证

  • @Xarvalus我想你可能会修改你的答案。看起来 `.and().securityContextRepository(NoOpServerSecurityContextRepository.getInstance())` 是主要解决方案,其余的可能完全是多余的:) (2认同)

小智 5

我通过以下技巧禁用了 WebSessionManager

  @Bean
  public WebSessionManager webSessionManager() {
    // Emulate SessionCreationPolicy.STATELESS
    return exchange -> Mono.empty();
  }
Run Code Online (Sandbox Code Playgroud)

所有其他解决方案对我都没有帮助。