捕获AuthenticationProvider中引发的exception

我正在实现自定义’AuthenticationProvider’。 如果未经过身份validation,我会在“authenticate”函数中抛出exception,如下所示。

public class DelegatingLdapAuthenticationProvider implements AuthenticationProvider { private ActiveDirectoryLdapAuthenticationProvider primaryProvider; private List secondaryProviders = new ArrayList(); public DelegatingLdapAuthenticationProvider() { } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { Authentication result = null; AuthenticationException exception = null; try { result = primaryProvider.authenticate(authentication); } catch (AuthenticationException e) { exception = e; for (ActiveDirectoryLdapAuthenticationProvider secondaryProvider : secondaryProviders) { try { result = secondaryProvider.authenticate(authentication); if (result.isAuthenticated()) { break; } } catch (AuthenticationException e1) { exception = e; } } } if (result == null || !result.isAuthenticated()) { throw exception; } return result; } 

我有全局exception处理程序,如下所示。

 @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler({NoPermissionException.class}) @ResponseBody @ResponseStatus(value = HttpStatus.FORBIDDEN) public Map noPermission(NoPermissionException e) { return createErrorResponse(e, "Don't have permissions"); } @ExceptionHandler({Exception.class}) @ResponseBody @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) public Map exceptionInProcessing(Exception e) { return createErrorResponse(e, "Unable to process. Unknown error occurred: " + e.getMessage()); } private Map createErrorResponse(Exception e, String errorMessage) { Map errorResponse = new HashMap(); errorResponse.put("message", errorMessage); errorResponse.put("reason", e.toString()); return errorResponse; } } 

当在“authenticate”函数内抛出exception时,不会调用全局exception处理程序。 对于所有其他exception,它被调用。 我想捕获全局exception处理程序中的exception并返回自定义错误消息。 我怎样才能做到这一点? 任何帮助赞赏。 提前致谢。

GlobalExceptionHandler用于控制器exception处理程序,但AuthenticationProvider仍处于filter中,如果要处理AuthenticationException ,则需要处理它以实现AuthenticationEntryPoint并覆盖commence方法。

 public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException 

AuthenticationExceptionAccessDeniedException已由ExceptionTranslationFilter处理。 您只需要注入AuthenticationEntryPointAccessDeniedHandler (处理AccessDeniedException

或者您可以在filter中捕获这些exception,然后在文件管理器中处理它,如AbstractAuthenticationProcessingFilter AuthenticationFailureHandler

在控制器exception处理程序有机会捕获exception之前调用身份validation提供程序。

您可以覆盖AuthenticationFailureHandler来处理安全filter链级别的exception,请查看示例

文档中描述的行为:

筛选器调用配置的AuthenticationManager来处理每个身份validation请求。 身份validation成功或身份validation失败后的目标分别由AuthenticationSuccessHandler和AuthenticationFailureHandler策略接口控制。 filter具有允许您设置这些属性的属性,以便您可以完全自定义行为

正如@chaoluo已经说过你需要实现AuthenticationEntryPoint并覆盖begin方法。 如果要返回错误JSON对象,可以执行以下操作:

 @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType(MediaType.APPLICATION_JSON_VALUE); //create errorObj PrintWriter writer = response.getWriter(); mapper.writeValue(writer, errorObj); writer.flush(); }