我希望提供一种基于 @kopelitsa的答案 的解决方案。 主要区别在于:
- 通过使用
HandlerExceptionResolver
重用控制器异常处理。
- 使用Java config而不是XML config。
首先,您需要确保有一个处理常规RestController/Controller中发生异常的类(一个带有@ RestControllerAdvice
或@ ControllerAdvice
注释和带有@ExceptionHandler
注释的方法)。这将处理控制器中发生的异常。以下是使用RestControllerAdvice的示例:
@RestControllerAdvice
public class ExceptionTranslator {
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorDTO processRuntimeException(RuntimeException e) {
return createErrorDTO(HttpStatus.INTERNAL_SERVER_ERROR, "An internal server error occurred.", e);
}
private ErrorDTO createErrorDTO(HttpStatus status, String message, Exception e) {
(...)
}
}
要在Spring Security过滤器链中重用此行为,您需要定义一个过滤器并将其挂接到安全配置中。该过滤器需要将异常重定向到上述定义的异常处理程序。以下是一个示例:
@Component
public class FilterChainExceptionHandler extends OncePerRequestFilter {
private final Logger log = LoggerFactory.getLogger(getClass());
@Autowired
@Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
filterChain.doFilter(request, response);
} catch (Exception e) {
log.error("Spring Security Filter Chain Exception:", e);
resolver.resolveException(request, response, null, e);
}
}
}
创建的过滤器需要添加到SecurityConfiguration中。您需要尽早将其钩入链中,因为所有先前过滤器的异常都不会被捕获。在我的情况下,将其添加到
LogoutFilter
之前是合理的。请参见默认的过滤器链及其顺序
在官方文档中。以下是一个例子:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private FilterChainExceptionHandler filterChainExceptionHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(filterChainExceptionHandler, LogoutFilter.class)
(...)
}
}