【问题标题】:Unable to return JSON data with Webflux authenticationFailureHandler无法使用 Webflux authenticationFailureHandler 返回 JSON 数据
【发布时间】:2019-07-05 02:01:36
【问题描述】:

我正在构建一个 React SPA,并希望使用 JSON 与后端进行交互。当身份验证失败时,我希望能够以 JSON 的形式发送自定义错误消息。但是给出下面的代码:

    .authenticationFailureHandler(((exchange, e) -> {
      return Mono.fromRunnable(() -> {
        ServerHttpResponse response = exchange.getExchange().getResponse();
        response.setStatusCode(HttpStatus.OK);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        DataBuffer buf = exchange.getExchange().getResponse().bufferFactory().wrap("{\"test\":\"tests\"}".getBytes(StandardCharsets.UTF_8));
        response.writeWith(Mono.just(buf));
      });
    })

我收到以下错误:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1 ; mode=block
Referrer-Policy: no-referrer
content-length: 0

<Response body is empty>

Response code: 200 (OK); Time: 1162ms; Content length: 0 bytes

但是,如果我更改响应代码,它会反映在响应中,因此我知道代码已执行但没有返回响应正文。

当身份验证失败时,我需要更改哪些内容才能发回响应正文?

【问题讨论】:

    标签: java spring-boot spring-security spring-webflux


    【解决方案1】:

    我认为这可行:

    .authenticationFailureHandler(((exchange, e) -> {
            ServerHttpResponse response = exchange.getExchange().getResponse();
            response.setStatusCode(HttpStatus.OK);
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            DataBuffer buf = exchange.getExchange().getResponse().bufferFactory().wrap("{\"test\":\"tests\"}".getBytes(StandardCharsets.UTF_8));
            return response.writeWith(Mono.just(buf));
          });
        })
    

    可能有比将 JSON 写为字符串更好的方法,但我相信这应该可行。 您的尝试没有奏效,因为没有订阅 response.writeWith(Mono.just(buf)) 返回的 Publisher。由于发布者很懒惰,因此不会向响应中写入任何内容。

    【讨论】:

      【解决方案2】:

      您也可以通过自定义 WebExceptionHandlerErrorAttributes 来实现此目的

      .authenticationFailureHandler(webFilterExchange, exception) ->
           customErrorWebExceptionHandler.handle(webFilterExchange.getExchange(), exception);
      
      
      @Component
      public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
      
          public CustomErrorWebExceptionHandler(
                  final CustomErrorAttributes customAttributes,
                  final ResourceProperties resourceProperties,
                  final ObjectProvider<List<ViewResolver>> viewResolversProvider,
                  final ServerCodecConfigurer serverCodecConfigurer,
                  final ApplicationContext applicationContext
          ) {
              super(customAttributes, resourceProperties, applicationContext);
      
              this.setViewResolvers(viewResolversProvider.getIfAvailable(Collections::emptyList));
              this.setMessageWriters(serverCodecConfigurer.getWriters());
              this.setMessageReaders(serverCodecConfigurer.getReaders());
          }
      
          @Override
          protected RouterFunction<ServerResponse> getRoutingFunction(final ErrorAttributes errorAttributes) {
      
              if (errorAttributes instanceof CustomErrorAttributes) {
                  return RouterFunctions.route(RequestPredicates.all(),
                      (request) -> handleProblemDetail(request, (CustomErrorAttributes) errorAttributes)
                              );
              }
              throw new UnsupportedOperationException(errorAttributes.getClass().getName());
          }
      
          private Mono<ServerResponse> handleProblemDetail(final ServerRequest request, final CustomErrorAttributes error) {
      
              final Map<String, Object> errorAttributes = error.getErrorAttributes(request, false);
      
              return ServerResponse.status(Integer.parseInt(errorAttributes
                      .getOrDefault("status", "500").toString()))
                      .contentType(MediaType.APPLICATION_PROBLEM_JSON)
                      .body(Mono.just(errorAttributes), Map.class)
      
                      ;
          }
      }
      
      
      @Component
      public class CustomErrorAttributes implements ErrorAttributes {
          private static final String ERROR_ATTRIBUTE = CustomErrorAttributes.class.getName() + ".ERROR";
      
          @Override
          public Map<String, Object> getErrorAttributes(final ServerRequest request, final boolean includeStackTrace) {
      
              final Throwable error = this.getError(request);
      
              return somethingThatConvertsTheErrorToAMap(error);
          }
      
          @Override
          public Throwable getError(final ServerRequest request) {
              return (Throwable)request.attribute(ERROR_ATTRIBUTE).orElseThrow(() -> {
                  return new IllegalStateException("Missing exception attribute in ServerWebExchange");
              });
          }
      
          @Override
          public void storeErrorInformation(final Throwable error, final ServerWebExchange exchange) {
              exchange.getAttributes().putIfAbsent(ERROR_ATTRIBUTE, error);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2019-03-20
        • 2020-01-23
        • 2019-08-13
        • 1970-01-01
        • 2018-11-08
        • 1970-01-01
        • 2016-08-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多