Spring Webflux Security / Reactive Exception Handling

I am building an application in spring webflux and I am stuck because spring security webflux (v.M5) did not behave like spring 4 in the exception handling process.

I saw the following message on how to configure spring security webflux: Spring webflux user authentication for API

If we make an exception, say in ServerSecurityContextRepository.load, spring will update the http header to 500, and I can do nothing to manipulate this exception.

However, any error that occurs in the controller can be handled using the usual @ControllerAdvice, it's just spring webflux security.

Is there a way to handle the exception in webflux spring security?

+4
source share
2 answers

I just went through a lot of documentation, having a similar problem.

My solution used a ResponseStatusException. AccessException for Spring-security seems understandable.

.doOnError(
          t -> AccessDeniedException.class.isAssignableFrom(t.getClass()),
          t -> AUDIT.error("Error {} {}, tried to access {}", t.getMessage(), principal, exchange.getRequest().getURI())) // if an error happens in the stream, show its message
.onErrorMap(
        SomeOtherException.class, 
        t -> { return new ResponseStatusException(HttpStatus.NOT_FOUND,  "Collection not found");})
      ;

If it goes in the right direction for you, I can provide a slightly better sample.

0
source

The solution I found is to create a component that implements ErrorWebExceptionHandler. ErrorWebExceptionHandlerBean instances run before Spring Security Filters. Here's the sample I'm using:

@Slf4j
@Component
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {

  @Autowired
  private DataBufferWriter bufferWriter;

  @Override
  public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
    HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
    AppError appError = ErrorCode.GENERIC.toAppError();

    if (ex instanceof AppException) {
        AppException ae = (AppException) ex;
        status = ae.getStatusCode();
        appError = new AppError(ae.getCode(), ae.getText());

        log.debug(appError.toString());
    } else {
        log.error(ex.getMessage(), ex);
    }

    if (exchange.getResponse().isCommitted()) {
        return Mono.error(ex);
    }

    exchange.getResponse().setStatusCode(status);
    return bufferWriter.write(exchange.getResponse(), appError);
  }
}

If you enter instead HttpHandler, then this is a little different, but the idea is the same.

0
source

Source: https://habr.com/ru/post/1691296/


All Articles