1.问题
使用SpringSecurity时候,自定义过滤器不走全局统一异常,走过滤器链异常处理
2. 全局统一异常
@RestControllerAdvice
@Slf4j
public class MyExceptionHandler {
@ExceptionHandler(CustomException.class)
public R commonException(CustomException e) {
log.debug("自定义异常信息:", e);
return R.error(e.getCode(), e.getMsg());
}
@ExceptionHandler(Exception.class)
public R handlerException(Exception e) {
log.error("系统异常信息:", e);
return R.error(StatusCode.FAIL);
}
}
3.自定义Filter
@WebFilter(urlPatterns = "/index/getSmsCode")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
...
throw new CustomException()
...
filterChain.doFilter(servletRequest, servletResponse);
}
}
要使上面@WebFilter生效,需要启动类添加@ServletComponentScan("路径"),
注意,若在上面过滤器中添加@component,则urlPatterns不生效,其他url也会走此过滤器
4.解决
全局统一异常处理只能处理控制器中发生的异常。要在Spring Security过滤器链中重用此功能,需要定义过滤器并将其挂钩到安全配置中。过滤器需要将异常重定向到统一异常处理中。
①.针对自定义,特定过滤器异常走全局异常
@WebFilter(urlPatterns = "/index/getSmsCode")
@Slf4j
public class SmsFilter implements Filter {
@Autowired
@Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
...
throw new CustomException(StatusCode.ERROR_PARAMETER);
...
filterChain.doFilter(servletRequest, servletResponse);
} catch (Exception e) {
resolver.resolveException((HttpServletRequest)request, (HttpServletResponse) servletResponse, null, e);
}
}
}
②.配置一处,是其他过滤器走全局也生效
自定义过滤器
@Component
public class FilterChainExceptionHandler extends OncePerRequestFilter {
@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)
(...)
}
}
参考: https://stackoverflow.com/questions/34595605/how-to-manage-exceptions-thrown-in-filters-in-spring