简体   繁体   English

如何使用 Spring WebFlux WebFilter 结束请求并发送正确的响应?

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

I am using JWT in header for verifying user request.我在标头中使用 JWT 来验证用户请求。

@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?它结束请求,但如何设置正确的响应? eg "Invalid token" OR "Internal Server Error" in response.例如“无效令牌”或“内部服务器错误”作为响应。

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.在 catch 块中,您可以执行以下操作或重新抛出异常,以便通过实现“org.springframework.web.server.WebExceptionHandler”来获得一些 GlobalExceptionHandler,并且您也可以拥有此逻辑。 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这里的关键是使用 DataBufferFactory 然后使用 Jackson 的 ObjectMapper 将您的自定义错误对象序列化为字符串,然后写入响应并使用 exchange.getResponse().setStatusCode 设置 HTTP 状态

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. ApiError 是一个自定义类,它具有 HTTP 状态和时间戳以及如下内容或您的自定义数据结构。

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();
       }





}

Maybe this will help, this is for x509 authentication but it will work for JWT.也许这会有所帮助,这适用于 x509 身份验证,但它适用于 JWT。

Check Authentication by certificate for WebFlux? 通过 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)使用身份验证转换器提取凭据(身份验证过滤器将负责调用 ReactiveAuthenticationManager 对提取的凭据进行身份验证)
  2. Use AuthenticationEntryEndpoint, if needed, to customize the response back to client in case of authentication failure如果需要,使用 AuthenticationEntryEndpoint 自定义在身份验证失败的情况下返回给客户端的响应

Hope this helps希望这有帮助

You can modify headers of Response:您可以修改响应的标头:

@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
        exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        exchange.getResponse().getHeaders().add("X-Message", "Unsupported Encoding");
        return Mono.empty();
    } catch (JWTVerificationException exception) {
        // send invalid token
        exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
        exchange.getResponse().getHeaders().add("X-Message", "Invalid token");
        return Mono.empty();
    }
    return chain.filter(exchange);
}

I couldn't find a way to write the body of Response我找不到写 Response 正文的方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM