Я настраиваю аутентификацию jwt в своем приложении для весенней загрузки и хочу обработать все исключения в одном месте.
Я знаю, что исключения из контроллеров можно обрабатывать в @ControllerAdvice
, для FilterSecurityInterceptor
Я могу установить AuthenticationEntryPoint
и AccessDeniedManager
, а для AuthenticationFilters
Я могу установить UnsuccessfulAuthentication
менеджер. Но кажется, что слишком много мест для обработки исключений.
Поэтому я хочу сделать его более централизованным.
Я решил просто отбросить все исключения, чтобы Tomcat
перенаправлял запросв "/error"
и устанавливает детали исключения в качестве атрибутов запроса. "/error"
обрабатывается контроллером, который извлекает исключение из запроса и перебрасывает его, поэтому исключение отправляется непосредственно обработчику исключений.
В моих фильтрах аутентификации (у меня есть пара из них) я делаюэто в конструкторе: this.setAuthenticationFailureHandler(
ExceptionHandlerUtils::authenticationFailureHandler);
public static void authenticationFailureHandler(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) {
throw authenticationException;
}
И то же самое для FilterSecurityInterceptor (в конфигурации безопасности):
@Override
protected void configure(HttpSecurity http) throws Exception {
...
http
.authenticationEntryPoint(ExceptionHandlerUtils::authenticationEntryPoint)
.accessDeniedHandler(ExceptionHandlerUtils::accessDeniedHandler);
...
}
Тогда из-за необработанного исключения (filterChain
didn 't обрабатывает исключения (за исключением некоторых AuthenticatoinException
и т. д.), обработка запроса возвращается к org.apache.catalina.core.StandardWrapperValve
, который, наконец, его перехватывает, делает это:
try {
*shortly, filterChain.doFilter(...)*
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
throwable = e;
exception(request, response, e);
}
Здесь происходит нежелательное ведение журнала и метод exception(...)
устанавливает исключение в качестве атрибута запроса, затем org.apache.catalina.core.StandardHostValve#throwable(...)
устанавливает некоторые другие атрибуты запроса и перенаправляет запрос на «/ error». Затем запрос снова проходит через цепочку к моему RethrowingErrorController
@RequestMapping("/error")
public Object getError(HttpServletRequest request) throws Throwable {
Object val = request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
if (val != null) {
throw (Throwable) val;
}
/* this should never be called, but whatever */
return "why are you here???";
}
и, наконец, обрабатывается
@ControllerAdvice
@Log4j2
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({RuntimeException.class})
protected ResponseEntity<Object> handleUnexpectedException(
RuntimeException ex, WebRequest request) {
log.error("unexpected conflict:", ex);
Map<?, ?> body = ExceptionHandlerUtils.getErrorAttributes(request, false);
return handleExceptionInternal(ex, body, new HttpHeaders(), HttpStatus.CONFLICT, request);
}
}
Этот подход позволяет мне обрабатывать все исключения, которые происходят в любом Controller
или Filter
(например, JwtAuthorizationFilter) в SpringSecurityFilterChain
в одном месте.
Однако перед тем, как tomcat перенаправляет запрос в «/ error», как описано выше, он жалуется на «внутреннюю ошибку» (мое исключение) в журналах. Я не хочу этого в журналах, потому что я все равно регистрирую ошибки в @ControllerAdvice
, а также я не хочу полностью отключать журналы tomcat.
Я могу отключить журналы из всего package org.apache.catalina.core;
в application.yml
logging:
level:
org.apache.catalina.core: off
Но я волнуюсь, что могу пропустить что-то важное позже. Поэтому мне нужно либо лучшее решение для централизации исключений, либо надежный способ скрыть нежелательные журналы ошибок.
Все предложения по улучшению моего вопроса очень приветствуются!