将 AccessDeniedException 传播到 Spring Security 3.2

Posted

技术标签:

【中文标题】将 AccessDeniedException 传播到 Spring Security 3.2【英文标题】:Propagate AccessDeniedException to Spring Security 3.2 【发布时间】:2015-09-04 16:39:48 【问题描述】:

我在 Spring Security 3.2 和 Spring 4.1.7 (Boot 1.2.5) 中使用全局方法安全性。 Spring 的全局方法安全拦截器抛出AccessDeniedException。但是,我有一个用@ControllerAdvice 注释的异常处理程序,并带有一个捕获ExceptionExceptionHandler 方法,因此AccessDeniedException 不会传播到Spring Security ExceptionResolvingFilter;因此,它不是由 Spring Security 处理的。

我尝试遵循here 的建议并创建了另一个专门处理AccessDeniedExceptionExceptionHandler 方法并简单地重新抛出它。但是这个例外再次没有弥补 Spring Security 的问题。它在第 366 行被 Spring 的 ExceptionHandlerExceptionResolver 吞噬:

// ============ SPRING'S EXCEPTIONHANDLEREXCEPTIONRESOLVER CODE ==========
try 
    if (logger.isDebugEnabled()) 
        logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);
    
    exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception);

catch (Exception invocationEx) 
    if (logger.isErrorEnabled()) 
        logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
    
    return null;

如何让AccessDeniedException 传播到 Spring Security?我必须创建一个自定义 ExceptionResolver 并继承并重写该方法吗?

【问题讨论】:

【参考方案1】:

您的代码吞下了异常

catch (Exception invocationEx) 
    if (logger.isErrorEnabled()) 
        logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
    
    return null; // here is the culprit

最好只是记录它或重新抛出它

catch (Exception invocationEx) 
    if (logger.isErrorEnabled()) 
        logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
    
    throw invocationEx;

【讨论】:

这就是问题所在:这不是我的代码,而是 Spring 的。 ExceptionHandlerExceptionResolver,第 366 行。【参考方案2】:

最后,我要做的就是在@ControllerAdvice 类中添加一个方法:

@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity<WebServiceResponse> handleAccessDeniedException(AccessDeniedException ex)

    WebServiceResponse response = new WebServiceResponseWithError(status: 'failure', message: ex.message, errorCode: 1007)
    return new ResponseEntity(response, HttpStatus.FORBIDDEN)

WebServiceResponse 是我为构建响应而编写的一个类。

这行得通,虽然我在模仿 Spring 的异常处理......

【讨论】:

【参考方案3】:

您也可以通过在@ControllerAdvice 类中添加以下代码来设置响应对象中的错误。

  @ExceptionHandler (value = AccessDeniedException.class)
  public void commence(HttpServletRequest request, HttpServletResponse response,
      AccessDeniedException accessDeniedException) throws IOException 
    response.sendError(HttpStatus.FORBIDDEN, accessDeniedException.getMessage());
   

【讨论】:

以上是关于将 AccessDeniedException 传播到 Spring Security 3.2的主要内容,如果未能解决你的问题,请参考以下文章

写入 JCR (JackRabbit) [Magnolia] 时出现 AccessDeniedException

由于错误 AccessDeniedException(Lambda 别名作为 Cognito 触发器),AWS Cognito 用户池引发 PreSignUp 调用失败

gsutil cors set 命令返回 403 AccessDeniedException

AccessDeniedException 上的 HTTP 401 [重复]

AccessDeniedException:用户无权对资源执行 dynamodb BatchWriteItem:表

收到 Spring MVC AccessDeniedException 500 错误,而不是 @PreAuthorized 未授权请求的自定义 401 错误