java - 如何使用spring security在spring-boot应用程序中集中异常处理?
问题描述
我正在我的 spring-boot 应用程序中设置 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
不处理异常 ( 除了 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);
}
}
这种方法允许我在一个地方处理任何Controller
或Filter
(如 JwtAuthorizationFilter)中发生的所有异常SpringSecurityFilterChain
。
但是,如上所述,在tomcat将请求重定向到“/error”之前,它会在日志中抱怨“内部错误”(我的异常)。我不想在日志中这样做,因为@ControllerAdvice
无论如何我都会记录错误,而且我也不想完全禁用 tomcat 日志。
我可以禁用整个package org.apache.catalina.core;
日志application.yml
logging:
level:
org.apache.catalina.core: off
但我很担心,我以后可能会错过一些重要的事情。所以,我需要一个更好的解决方案来集中异常,或者一个可靠的方法来隐藏不需要的错误日志。
非常欢迎所有改善我的问题的建议!
解决方案
推荐阅读
- css - 在没有固定高度的父项中控制 Flex 子项的比率
- python - 如何在google colab中基于python变量查找和执行
- gradle - 如何在 MarkLogic 中清除模块数据库
- java - 当我单击确定时,弹出窗口是空白的
- r - ggplot中的时间序列差异
- c# - 创建新 XFont 时出现异常。PDFSharp Xamarin
- javascript - 当从 Promise 而不是数字跟随时,等待行为应该不同吗?
- react-native - 只安装一次组件,不再卸载它
- c# - 为 Android 设置底部选项卡式导航时应用程序崩溃
- matlab - 如何移动分组条形图的位置?