无法使用Webflux authenticationFailureHandler返回JSON数据

时间:2019-02-11 14:35:04

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

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

chart.getDatasetMeta(0)

出现以下错误:

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

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

我需要更改什么才能在身份验证失败时发送回响应正文?

2 个答案:

答案 0 :(得分:0)

我认为这可行:

.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编写为String更好的方法,但是我认为这应该可行。 您的尝试没有用,因为Publisher没有订阅返回的response.writeWith(Mono.just(buf))。由于发布者很懒,因此不会在响应中写入任何内容。

答案 1 :(得分:0)

您还可以使用自定义的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);
    }
}