Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to end request and send proper response using Spring WebFlux WebFilter?

I am using JWT in header for verifying user request.

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
    String token = exchange.getRequest().getHeaders().getFirst("token");
    // Verify a Token
    try {
        Algorithm algorithm = Algorithm.HMAC256("secret");
        JWTVerifier verifier = JWT.require(algorithm)
                .withIssuer("auth0")
                .build(); //Reusable verifier instance
        DecodedJWT jwt = verifier.verify(token);
    } catch (UnsupportedEncodingException exception) {
        // send internal server error in response
    } catch (JWTVerificationException exception) {
        // send invalid token
    }
    return chain.filter(exchange);
}

When I use

return Mono.empty();

It ends requests, but how to set a proper response? e.g. "Invalid token" OR "Internal Server Error" in response.

like image 411
Roshan Gade Avatar asked Oct 30 '25 05:10

Roshan Gade


2 Answers

In the catch block you can do the following or rethrow the exception so you have some GlobalExceptionHandler by implementing "org.springframework.web.server.WebExceptionHandler" and there you can have this logic as well. The Key here is using DataBufferFactory and then using ObjectMapper of Jackson to serialize your custom error object to string and then write the response as well as set the HTTP Status using exchange.getResponse().setStatusCode

import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@Autowired
    ObjectMapper objMapper;

        ApiError apiError = new ApiError(HttpStatus.UNAUTHORIZED);
        apiError.setTimestamp(LocalDateTime.now());
        apiError.setMessage("Invalid token" + exception.getMessage() + ":"+exception.getLocalizedMessage());
        DataBuffer buf = null;
        try {
            buf = dataBufferFactory.wrap(objMapper.writeValueAsBytes(apiError));
        } catch (JsonProcessingException e) {
            LOG.debug("Exception during processing JSON", e);
            apiError.setMessage(e.getMessage());
        }
        if(buf == null) buf = dataBufferFactory.wrap("".getBytes());
        exchange.getResponse().setStatusCode(apiError.getStatus());
        return exchange.getResponse().writeWith(Flux.just(buf));

ApiError is a custom class that has HTTP Status and timestamp and stuff like below or your custom datastructure as well.

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;

import org.springframework.http.HttpStatus;

import com.fasterxml.jackson.annotation.JsonFormat;

import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ApiError  implements Serializable{

       private HttpStatus status;
       @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "MM/dd/yyyy hh:mm:ss a")
       private LocalDateTime timestamp;
       private String message;
       private String debugMessage;


       public ApiError() {
           timestamp = LocalDateTime.now();
       }

       public ApiError(HttpStatus status) {
           this();
           this.status = status;
       }

       public ApiError(HttpStatus status, Throwable ex) {
           this();
           this.status = status;
           this.message = "Unexpected error";
           this.debugMessage = ex.getLocalizedMessage();
       }

       public ApiError(HttpStatus status, String message, Throwable ex) {
           this();
           this.status = status;
           this.message = message;
           this.debugMessage = ex.getLocalizedMessage();
       }





}
like image 191
ROCKY Avatar answered Oct 31 '25 19:10

ROCKY


Maybe this will help, this is for x509 authentication but it will work for JWT.

Check Authentication by certificate for WebFlux?

Key points are:

  1. Use the authentication converter to extract credentials (the authentication filter will take care of calling the ReactiveAuthenticationManager to authenticate the extracted credentials)
  2. Use AuthenticationEntryEndpoint, if needed, to customize the response back to client in case of authentication failure

Hope this helps

like image 39
bsamartins Avatar answered Oct 31 '25 18:10

bsamartins



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!