如何优雅地处理未在ControllerAdvice中处理的Spring Security中的异常?

时间:2016-03-18 17:01:49

标签: spring-mvc spring-security error-handling

我最近在Spring 4 / Hibernate Web应用程序中实现了Spring Security,以处理登录/退出和不同的用户角色。

经过大量阅读后,它现在看起来工作得很好,但是我注意到由于错误的Spring Security配置引发的异常没有使用我的自定义处理程序正常处理,但显示为丑陋的Tomcat错误页面(显示HTTP状态500) - 需要UserDetailsS​​ervice,然后是stacktrace)。

解决特定错误并不困难(在RememberMe配置中添加userDetailsS​​ervice(userDetailsS​​ervice))但事实仍然是抛出的某些异常不会由 下面显示的ControllerAdvice处理MaxUploadSizeExceededException和所有其他运行时异常:

@ControllerAdvice
public class ExceptionHandlingControllerAdvice {

public static final String DEFAULT_ERROR_VIEW = "genericerror";

@ExceptionHandler(value = MaxUploadSizeExceededException.class)
public View maxUploadSizeExceededExceptionHandler(
        HttpServletRequest req) throws IOException {

    String redirectUrl = req.getRequestURL().toString();

    RedirectView rv = new RedirectView(redirectUrl);

    FlashMap outputFlashMap = RequestContextUtils.getOutputFlashMap(req);
    if (outputFlashMap != null) {
        outputFlashMap.put(KeyConstants.FLASH_ERROR_KEY, "Bestand is te groot");
    }
    return rv;
}

@ExceptionHandler(value = RuntimeException.class)
public View defaultErrorHandler(HttpServletRequest req, Exception e) {

    RedirectView rv = new RedirectView("/error", true); //context relative

    StackTraceElement[] steArray = e.getStackTrace();
    StringBuilder stackTrace = new StringBuilder();
    for (StackTraceElement element: steArray) {
        stackTrace.append(element.toString() + "\n");
    }

    FlashMap outputFlashMap = RequestContextUtils.getOutputFlashMap(req);
    if (outputFlashMap != null) {
        outputFlashMap.put("url", req.getRequestURL());
        outputFlashMap.put("excClassName", e.getClass().getName());
        outputFlashMap.put("excMessage", e.getMessage());
        outputFlashMap.put("excStacktrace", stackTrace.toString());
    }
    e.printStackTrace();

    return rv;
}
}

但是,未完成配置的安全性抛出的异常可能不会被此机制捕获,因为在调用任何控制器方法之前,Spring Security会截获登录POST请求。我想在自定义错误页面上以优雅的方式显示所有异常,也就是在Controller到位之前抛出的异常。

我找不到很多相关信息,Spring手册(http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers)中描述的所有错误处理技术似乎都使用了Controller建议。

是否有通过通用方式处理所有异常的便捷方法?并使我的Controller建议类处理多余的异常?

2 个答案:

答案 0 :(得分:8)

正如您所注意到的那样,@ExceptionHandler对于抛出外部(在堆中的位置比)Spring MVC的异常不起作用。

您可以通过在web.xml中指定错误页面来捕获未在其他地方捕获的所有异常:

<error-page>
  <exception-type>java.lang.Throwable</exception-type>
  <location>/500</location>
</error-page>

您将此500页设为普通页面,通常在Spring MVC中:

@RequestMapping(value="/500")
public @ResponseBody String handleException(HttpServletRequest req) {

    // this will get the exception thrown/caught
    Throwable exception = (Throwable)req.getAttribute("javax.servlet.error.exception");

    // customize the response as you want
    return "Internal server error.";
}

答案 1 :(得分:3)

如果你使用的是Spring Boot,你可以创建一个自定义的ErrorController,你手边有一个名为BasicErrorController的默认值。