Spring Security - Ajax 调用忽略 @ExceptionHandler

Posted

技术标签:

【中文标题】Spring Security - Ajax 调用忽略 @ExceptionHandler【英文标题】:Spring Security - Ajax calls ignoring @ExceptionHandler 【发布时间】:2016-08-15 20:12:19 【问题描述】:

我的项目中有一个控制器来处理所有定义如下的异常:

@ControllerAdvice
public class GlobalExceptionHandlingController 

    @ResponseBody
    @ExceptionHandler(value = AccessDeniedException.class)
    public ResponseEntity accessDeniedException() 
        Logger.getLogger("#").log(Level.SEVERE, "Exception caught!");
        return new ResponseEntity("Access is denied", HttpStatus.FORBIDDEN);
    


我在这里关注一个特定的异常,即 Spring Security 在未经授权的请求时抛出的 AccessDeniedException。这适用于“正常”又名非 ajax 请求。我可以点击链接或直接在地址栏中输入 URL,如果请求未经授权,我会看到此消息。

但是在 AJAX 请求(使用 Angular)时,我收到标准 403 错误页面作为响应,但有趣的是我可以看到 AccessDeniedException 被此控制器捕获!

我做了一些研究,似乎我需要自定义 AccessDeniedHandler,所以我做了这个:

在我的 Spring Security 配置中添加了这一行:

.and()
.exceptionHandling().accessDeniedPage("/error/403/");

我制作了特殊的控制器来处理这个问题:

@Controller
public class AjaxErrorController 

    @ResponseBody
    @RequestMapping(value = "/error/403/", method = RequestMethod.GET)
    public ResponseEntity accessDeniedException() 
        return new ResponseEntity("Access is denied (AJAX)", HttpStatus.FORBIDDEN);
    


现在这工作正常,但异常仍被第一个控制器捕获,但该方法的返回值被忽略。为什么?

这是应该的吗?我有一种感觉,我在这里遗漏了一些东西。

我正在使用 Spring 4.2.5 和 Spring Security 4.0.4。

【问题讨论】:

【参考方案1】:

虽然我不知道所有细节,但我的理论是它可能是内容类型问题。

通常在做 AJAX 请求时,响应应该是 JSON 格式,所以浏览器会在请求中添加一个Accept: application/json 标头。

另一方面,您的响应实体:

new ResponseEntity("Access is denied", HttpStatus.FORBIDDEN)

是文本响应,典型 Spring 设置的默认 Content-Type 是 text/plain

当 Spring 检测到它无法传递客户端所需类型的响应时,它会回退到默认错误页面。

【讨论】:

以上是关于Spring Security - Ajax 调用忽略 @ExceptionHandler的主要内容,如果未能解决你的问题,请参考以下文章

用于ajax调用的spring security csrf保护

Spring Security CSRF 令牌不适用于 AJAX 调用和表单提交在同一个 JSP 中

ajax请求在spring security中被拒绝,Grails

Jersey Spring-Security HTML AJAX 未按预期工作

Grails Spring Security - 会话超时后重新登录时重新加载会话变量

Spring Security入门(3-7)Spring Security处理页面的ajax请求