首页 > 解决方案 > 如何使用spring security在spring-boot应用程序中集中异常处理?

问题描述

我正在我的 spring-boot 应用程序中设置 jwt 身份验证,我想在一个地方处理所有异常。

我知道控制器的异常可以在 中处理@ControllerAdvice,因为FilterSecurityInterceptor我可以设置AuthenticationEntryPointAccessDeniedManager,并且我可以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不处理异常 ( 除了 someAuthenticatoinException等),请求处理回滚到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);
    }

}

这种方法允许我在一个地方处理任何ControllerFilter(如 JwtAuthorizationFilter)中发生的所有异常SpringSecurityFilterChain

但是,如上所述,在tomcat将请求重定向到“/error”之前,它会在日志中抱怨“内部错误”(我的异常)。我不想在日志中这样做,因为@ControllerAdvice无论如何我都会记录错误,而且我也不想完全禁用 tomcat 日志。

我可以禁用整个package org.apache.catalina.core;日志application.yml

logging:
  level:
    org.apache.catalina.core: off

但我很担心,我以后可能会错过一些重要的事情。所以,我需要一个更好的解决方案来集中异常,或者一个可靠的方法来隐藏不需要的错误日志。

非常欢迎所有改善我的问题的建议!

标签: javaspringexceptionspring-security

解决方案


推荐阅读