最佳答案
我使用 Spring MVC 的 @ControllerAdvice
和 @ExceptionHandler
来处理 REST Api 之外的所有异常。它对 web mvc 控制器引发的异常可以正常工作,但对 Spring 安全自定义过滤器引发的异常无效,因为它们在调用控制器方法之前运行。
我有一个自定义的 Spring 安全过滤器,它执行基于令牌的认证:
public class AegisAuthenticationFilter extends GenericFilterBean {
...
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
try {
...
} catch(AuthenticationException authenticationException) {
SecurityContextHolder.clearContext();
authenticationEntryPoint.commence(request, response, authenticationException);
}
}
}
通过这个自定义入口点:
@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
}
}
使用这个类可以全局处理异常:
@ControllerAdvice
public class RestEntityResponseExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({ InvalidTokenException.class, AuthenticationException.class })
@ResponseStatus(value = HttpStatus.UNAUTHORIZED)
@ResponseBody
public RestError handleAuthenticationException(Exception ex) {
int errorCode = AegisErrorCode.GenericAuthenticationError;
if(ex instanceof AegisException) {
errorCode = ((AegisException)ex).getCode();
}
RestError re = new RestError(
HttpStatus.UNAUTHORIZED,
errorCode,
"...",
ex.getMessage());
return re;
}
}
我需要做的是返回一个详细的 JSON 主体,即使是针对春季安全 AuthenticationException。有没有办法让 spring security AuthenticationEntryPoint 和 spring mvc@ExceptionHandler 一起工作?
我用的是弹簧安全3.1.4和弹簧 mvc 3.2.4。