Я создал следующий пользовательский фильтр, который будет использоваться для авторизации в приложении 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.@ControllerAdvice.На данный момент это скорее неприятность, чем блокировщик, потому что на самом деле выдача ResponseStatusException из облачного фильтра с пользовательским кодом ошибки фактически возвращает этот код ошибки вызывающей стороне. Но было бы неплохо обрабатывать все исключения в одном месте.
Кто-нибудь может пролить свет на эту проблему?
@luboskrnac Я этого не знаю, поэтому я задал вопрос :-) ... доступная документация для шлюза Spring Cloud довольно скудна, оставляя единственные реальные варианты, такие как переполнение стека или самостоятельное чтение исходного кода.
Spring должен знать об этом фильтре, чтобы применить его. Можете ли вы показать полный класс? Обычно фильтры сервлетов подключаются к вашей конфигурации Spring Security. Если этот фильтр применяется, в вашем приложении уже есть какой-то механизм.
Это не веб-фильтр J2EE, и хотя он может подключаться к Spring Security под капотом, такие детали реализации скрыты от тех, кто использует Spring Cloud.
Spring Cloud — это просто набор помощников для интеграции с распространенными облачными шаблонами/сервисами. Spring Boot (с помощью Spring MVC и Spring Security + контейнер сервлетов) обрабатывает запросы. Так что по сути это стандартный фильтр сервлетов из мира J2EE.
@luboskrnac Хорошо, продолжая ваш комментарий, есть ли какое-либо общее средство, позволяющее заставить @ControllerAdvice работать с исключениями, поступающими из фильтров J2EE?
@ControllerAdvice не работает с фильтрами Spring Cloud Gateway.
@spencergibb Привет, Спенсер, спасибо, что прочитали мой вопрос. Я в основном должен прийти к этому выводу уже. Не могли бы вы опубликовать ответ о наилучшей практике создания исключения из облачного фильтра?




Classes with @ControllerAdvice can be declared explicitly as Spring beans or auto-detected via classpath scanning.
Вы не показали полный класс для своего фильтра, но могу поспорить, что это не Spring Bean, просканированный в пути к классам. Обычно фильтры сервлетов явно подключаются к конфигурации Spring Security. Поэтому обработка ControllerAdvice игнорирует его.
Облачный фильтр находится в каталоге filter, который находится непосредственно под классом, содержащим контроллер @SpringBootApplication.
Я предполагаю, что под фильтром вы имеете в виду javax.servlet.Filter.
В этом случае @ControllerAdvice не работает. Он используется для обработки исключений от контроллеров. Но вы выбрасываете исключение еще до того, как оно сможет распространиться на контроллер (не вызывая метод 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 делает внутри.
Интересное предложение. Итак, в этом случае будет ли правильным шаблоном просто генерировать исключения терминала непосредственно из пользовательского облачного фильтра?
Отредактировано, чтобы ответить на ваш дополнительный вопрос.
Можете ли вы также показать механизм, как этот фильтр подключается к цепочке обработки сервлетов?