如何捕获Spring Security Matchers抛出的异常?

时间:2019-09-18 08:16:19

标签: java exception spring-security

我有一个受 $.ajax({ data:number, dataType: "json", type:"POST", url : "payment/request1", cache: false, success: function (response) { console.log(response); if(response === true){ $.colorbox({html:'<div id="paymentblock"><div><h2 style="color:#444;">Open app in your phone</h2></div><div style="text-align:center;"><p>Payment with '+number+'</p><img src="/images/giphy.gif"></div>'}); $('#edit-commerce-payment-payment-details-number').css('background','#fff').val(''); $('#colorbox').colorbox({ onComplete: function () { $(this).colorbox.resize(); } }); }else{ $.colorbox({html:'<div id="paymentblock"><div><h2 style="color:#444;">An error occurred</h2></div><div style="text-align:center;"><p>Kontakta oss.</p></div>'}); $('#colorbox').colorbox({ onComplete: function () { $(this).colorbox.resize(); } }); } } }); 配置的spring security保护的后端,例如 antMatchers()

在同一应用中,我使用.antMatchers("/api/myProtectedUri/*").authenticated()@ControllerAdvice来处理引发的异常。为了防止API从后端返回不受控制的响应(例如stacktraces),我编写了以下内容:

@ExceptionHandler

这导致测试失败,因为处理程序还可能在保护端点的同时捕获了spring安全性引发的异常,所以状态代码为500(来自处理程序),而不是预期的401或403(来自spring)

我尝试使用自定义处理程序,例如:

@ExceptionHandler({RuntimeException.class})
public ResponseEntity handleRuntimeException()  {
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Unexpected error occurred");
}

它仍然被带有RuntimeException子句的@ExceptionHandler捕获。

我的问题是:

  1. Spring Security抛出哪些异常(如果我知道的话,我可以单独处理它们)
  2. 单独捕获异常的想法是否可以解决问题,也许还有另一种解决方案,可以更好地完成我想做的事情?

1 个答案:

答案 0 :(得分:0)

Spring安全性基于过滤器,而Spring MVC基于servlet,@ExceptionHandler不应捕获Spring安全性引发的异常。

.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler())

这是一个ExceptionTranslationFilter,它将处理AuthenticationExceptionAccessDeniedException,源代码请参见here

            Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(var10);
            RuntimeException ase = (AuthenticationException)this.throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
            if (ase == null) {
                ase = (AccessDeniedException)this.throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
            }

            if (ase == null) {
                if (var10 instanceof ServletException) {
                    throw (ServletException)var10;
                }

                if (var10 instanceof RuntimeException) {
                    throw (RuntimeException)var10;
                }

                throw new RuntimeException(var10);
            }

            if (response.isCommitted()) {
                throw new ServletException("Unable to handle the Spring Security Exception because the response is already committed.", var10);
            }

            this.handleSpringSecurityException(request, response, chain, (RuntimeException)ase);

AuthenticationException(通常表示未通过身份验证)将由AuthenticationEntryPoint处理,您可以实现自己的AuthenticationEntryPoint,只需覆盖commence方法,例如HttpStatusEntryPoint,它只是返回具有客户状态的响应。

public final class HttpStatusEntryPoint implements AuthenticationEntryPoint {
    private final HttpStatus httpStatus;

    public HttpStatusEntryPoint(HttpStatus httpStatus) {
        Assert.notNull(httpStatus, "httpStatus cannot be null");
        this.httpStatus = httpStatus;
    }

    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setStatus(this.httpStatus.value());
    }
}

,您可以将入口点设置为异常处理。

exceptionHandling()
    .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))

AccessDeniedHandler(通常表示未经授权)将由您完成的AccessDeniedHandler处理。