Как централизовать обработку исключений в Spring-boot приложении с помощью Spring Security? - PullRequest
3 голосов
/ 30 сентября 2019

Я настраиваю аутентификацию 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

Но я волнуюсь, что могу пропустить что-то важное позже. Поэтому мне нужно либо лучшее решение для централизации исключений, либо надежный способ скрыть нежелательные журналы ошибок.

Все предложения по улучшению моего вопроса очень приветствуются!

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