Обработчик @ControllerAdvice не вызывается из пользовательского фильтра Spring Cloud - PullRequest
0 голосов
/ 01 апреля 2019

Я создал следующий пользовательский фильтр, который будет использоваться для авторизации в приложении Spring Cloud. Вот метод apply() из этого фильтра, из которого выдается исключение в случае неудачной проверки авторизации:

@Override
public GatewayFilter apply(Config config) {
    return (exchange, chain) -> {
        HttpStatus status = HttpStatus.FORBIDDEN;

        try {
            String authRequest = exchange.getRequest().getHeaders().getFirst(
                 Constants.SESSION_HEADER_NAME);
            HttpHeaders headers = new HttpHeaders();
            HttpEntity<String> entity = new HttpEntity<String>(authRequest, headers);
            // make REST call to authorization module
            status = restTemplate.postForEntity(authURL, entity, String.class).getStatusCode();
        }
        catch (Exception e) {
            LOGGER.error("Something went wrong during authorization", e);
        }

        // throw an exception if anything went
        // wrong with authorization
        if (!HttpStatus.OK.equals(status)) {
            throw new ResponseStatusException(HttpStatus.FORBIDDEN);
        }

        return chain.filter(exchange);
    };
}

Я определил следующий класс @ControllerAdvice для перехвата всех исключений, генерируемых вышеуказанным фильтром Gateway Cloud:

@ControllerAdvice
public class RestExceptionHandler {
    @ExceptionHandler(value = ResponseStatusException.class)
    public final ResponseEntity<Object> handleException(ResponseStatusException ex) {
        return new ResponseEntity<>("UNAUTHORIZED", HttpStatus.FORBIDDEN);
    }
}

В настоящее время я наблюдаю следующее:

  • Вышеуказанный пользовательский фильтр ResponseStatusException - это , а не , перехваченный методом отображения @ControllerAdvice.
  • Тем не менее, выбрасывая это исключение из другого места в приложении Spring Boot, например обычный контроллер, который мы используем в качестве конечной точки аутентификации, - это , перехваченный методом @ControllerAdvice.

Пока что это больше неприятность, чем блокировщик, потому что на самом деле выбрасывание ResponseStatusException из фильтра Cloud с пользовательским кодом ошибки фактически возвращает этот код ошибки вызывающей стороне. Но было бы неплохо обработать все исключения в одном месте.

Может кто-нибудь пролить свет на эту проблему?

Ответы [ 2 ]

0 голосов
/ 01 апреля 2019

Я предполагаю, что под фильтром вы подразумеваете javax.servlet.Filter.

В этом случае @ControllerAdvice не может работать. Он используется для обработки исключений из контроллеров. Но вы бросаете Exception, прежде чем он сможет распространиться на контроллер (не вызывая метод chain.filter(exchange).

Попробуйте выбросить исключения в контроллере, а не в фильтре.

Редактировать: Если вы не хотите обрабатывать исключения на @Controller, вы должны реализовать обработчик терминала в javax.servlet.Filter напрямую. Это означает, что измените ответ на входящий запрос напрямую следующим образом:

HttpServletResponse httpResponse = (HttpServletResponse) exchange.getResponse();

// either format the response by yourself
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpResponse.setHeader(...)
...

// or let populate error directly
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);

... это то, что @ControllerAdvice делает внутренне.

0 голосов
/ 01 апреля 2019

С ControllerAdvice javadocs :

Классы с @ControllerAdvice могут быть явно объявлены как бины Spring или автоматически обнаружены с помощью сканирования пути к классам.

Вы не показали полный класс для своего фильтра, но держу пари, это не Spring Bean, отсканированный на пути к классамОбычно фильтры сервлетов явно подключаются к конфигурации Spring Security.Поэтому обработка ControllerAdvice игнорирует его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...