繁体   English   中英

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

[英]How to catch the exceptions thrown by spring security matchers?

我有一个受弹簧安全性保护的后端,该安全性由antMatchers()配置,如.antMatchers("/api/myProtectedUri/*").authenticated()

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

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

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

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

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

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

我的问题是:

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

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

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

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

            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处理,您可以实现自己的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处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM