使用@ExceptionHandler 处理 spring security 认证异常

新手上路,请多包涵

我正在使用 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。

原文由 Nicola 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 954
2 个回答

好的,我尝试按照建议从 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,但您会序列化一些类实例。

在 Spring Boot 中,您应该将其添加到 SecurityConfiguration 文件的 http.authenticationEntryPoint() 部分。

原文由 Nicola 发布,翻译遵循 CC BY-SA 4.0 许可协议

我发现的最好方法是将异常委托给 HandlerExceptionResolver

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

    @Autowired
    private HandlerExceptionResolver resolver;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        resolver.resolveException(request, response, null, exception);
    }
}

然后您可以使用 @ExceptionHandler 以您想要的方式格式化响应。

原文由 Christophe Bornet 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题