一尘不染

使用@ExceptionHandler处理Spring Security身份验证异常

spring

我正在使用Spring MVC @ControllerAdvice@ExceptionHandler处理REST Api的所有异常。对于Web MVC控制器抛出的异常,它工作正常,但对于Spring Security自定义过滤器抛出的异常,它不工作,因为它们在调用控制器方法之前运行。

我有一个自定义的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主体,即使对于spring security AuthenticationException也是如此。有没有办法使Spring Security AuthenticationEntryPoint和Spring MVC @ExceptionHandler一起工作?

我正在使用Spring Security 3.1.4和Spring MVC 3.2.4。


阅读 1361

收藏
2020-04-12

共1个答案

一尘不染

我尝试按照建议从AuthenticationEntryPoint自己编写json,它可以工作。

仅出于测试目的,我通过删除response.sendError更改了AutenticationEntryPoint

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{

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

        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getOutputStream().println("{ \"error\": \"" + authenticationException.getMessage() + "\" }");

    }
}

这样,即使您使用的是Spring Security AuthenticationEntryPoint,也可以将自定义json数据与未经授权的401一起发送。

显然,您不会像我出于测试目的那样构建json,但会序列化一些类实例。

2020-04-12