Describe the bug

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
      return chain.filter(exchange).onErrorResume(AccessDeniedException.class, (denied) -> exchange.getPrincipal()
              .filter((principal) -> (!(principal instanceof Authentication) || (principal instanceof Authentication
                      && !(this.authenticationTrustResolver.isAnonymous((Authentication) principal)))))
              .switchIfEmpty(commenceAuthentication(exchange,
            new InsufficientAuthenticationException(
                    "Full authentication is required to access this resource")))
              .flatMap((principal) -> this.accessDeniedHandler.handle(exchange, denied)).then());
  }

switchIfEmpty always call commenceAuthentication even if the return value of filter is non empty Mono. To Reproduce Steps to reproduce the behavior.

Expected behavior I'm a new in Reactor, I wanna know whether it's suitable to use Mono.defer() here.

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
    return chain.filter(exchange).onErrorResume(AccessDeniedException.class, (denied) -> exchange.getPrincipal()
            .filter((principal) -> (!(principal instanceof Authentication) || (principal instanceof Authentication
                    && !(this.authenticationTrustResolver.isAnonymous((Authentication) principal)))))
            .switchIfEmpty(Mono.defer(() -> commenceAuthentication(exchange,
                    new InsufficientAuthenticationException(
                            "Full authentication is required to access this resource"))))
            .flatMap((principal) -> this.accessDeniedHandler.handle(exchange, denied)).then());
}

Sample

A link to a GitHub repository with a minimal, reproducible sample.

Reports that include a sample will take priority over reports that do not. At times, we may require a sample, so it is good to try and include a sample up front.

Comment From: ccwxl

I also encountered the same problem. How did you solve it?

Comment From: ccwxl

why close?

Comment From: YazidLee

why close?

I went through several implementations in the Spring security library, for example: org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint Their commence methods are all wrapped with a deferred Mono by using Mono.defer or Mono.fromRunnable, like:

public class HttpBasicServerAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
    // ...
    @Override
    public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException ex) {
        return Mono.fromRunnable(() -> {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            response.getHeaders().set(WWW_AUTHENTICATE, this.headerValue);
        });
    }
    // ...
}