【问题标题】:How to end request and send proper response using Spring WebFlux WebFilter?如何使用 Spring WebFlux WebFilter 结束请求并发送正确的响应?
【发布时间】:2018-07-05 17:54:34
【问题描述】:

我在标头中使用 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);
}

当我使用时

return Mono.empty();

它结束请求,但是如何设置正确的响应?例如响应为“无效令牌”或“内部服务器错误”。

【问题讨论】:

    标签: java spring jwt spring-webflux


    【解决方案1】:

    在 catch 块中,您可以执行以下操作或重新抛出异常,这样您就可以通过实现“org.springframework.web.server.WebExceptionHandler”来获得一些 GlobalExceptionHandler,并且您也可以拥有这个逻辑。这里的关键是使用 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 是一个自定义类,它具有 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();
           }
    
    
    
    
    
    }
    

    【讨论】:

      【解决方案2】:

      也许这会有所帮助,这适用于 x509 身份验证,但适用于 JWT。

      查看Authentication by certificate for WebFlux?

      重点是:

      1. 使用身份验证转换器提取凭据(身份验证过滤器将负责调用 ReactiveAuthenticationManager 以对提取的凭据进行身份验证)
      2. 如果需要,使用 AuthenticationEntryEndpoint 自定义在身份验证失败时返回给客户端的响应

      希望对你有帮助

      【讨论】:

        【解决方案3】:

        您可以修改响应的标题:

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

        我找不到写响应正文的方法

        【讨论】:

          猜你喜欢
          • 2021-10-26
          • 2019-01-15
          • 1970-01-01
          • 2020-07-24
          • 1970-01-01
          • 2017-11-08
          • 2018-03-20
          • 2018-10-07
          • 1970-01-01
          相关资源
          最近更新 更多