【问题标题】:Disable WebSession creation when using spring-security with spring-webflux将 spring-security 与 spring-webflux 一起使用时禁用 WebSession 创建
【发布时间】: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);
                   }
               });
           }
       };
   }

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

【问题讨论】:

    标签: java spring-security spring-webflux


    【解决方案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,您还可以禁用所有安全功能,并用您的自定义实现替换authenticationManagersecurityContextRepository ,去除基于会话的功能:

    @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 的家伙有点来回折腾,他们有很多关于处理和安全的正在进行的项目......
        猜你喜欢
        • 2020-04-10
        • 2021-05-06
        • 2022-12-15
        • 2011-01-15
        • 2021-09-03
        • 2011-01-23
        • 2014-12-20
        • 1970-01-01
        • 2011-04-16
        相关资源
        最近更新 更多