首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在Spring Boot REST API中捕获AccessDeniedException

如何在Spring Boot REST API中捕获AccessDeniedException
EN

Stack Overflow用户
提问于 2017-07-26 12:43:05
回答 2查看 9.2K关注 0票数 3

我有一个简单的Spring Boot REST API,有两个端点,一个是受保护的,另一个不是。对于受保护的错误,我希望捕获AccessDeniedException并发送401错误,而不是默认的500错误。下面是我的安全配置:

代码语言:javascript
运行
复制
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

@Override
public void configure(WebSecurity webSecurity) {
    webSecurity.ignoring().antMatchers("/");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .exceptionHandling()
            .accessDeniedHandler(new AccessDeniedHandler() {
                @Override
                public void handle(HttpServletRequest request, HttpServletResponse response, org.springframework.security.access.AccessDeniedException accessDeniedException) throws IOException, ServletException {
                    System.out.println("I am here now!!!");
                }
            });

    http
            .addFilterAfter(getSecurityFilter(), FilterSecurityInterceptor.class);
    http
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    http
            .csrf()
            .disable();
    http
            .authorizeRequests()
            .antMatchers("/protected").anonymous();
}

public Filter getSecurityFilter() {
    return new Filter() {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            //do nothing here
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            String appKeyHeaderValue = ((HttpServletRequest)request).getHeader("X-AppKey");
            if(appKeyHeaderValue!=null && appKeyHeaderValue.equals("MY_KEY")) {
                chain.doFilter(request,response);
            } else {
                throw new AccessDeniedException("Access denied man");
            }
        }

        @Override
        public void destroy() {

        }
    };
}

}

我从来没有看到过我的I am here now!!!打印语句,相反,我看到的是默认页面Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Tue Jul 25 23:21:15 CDT 2017 There was an unexpected error (type=Internal Server Error, status=500). Access denied man注意当异常被抛出时,我的Access denied man是如何打印的。

当我运行该项目时,我还在控制台中看到以下内容:2017-07-25 23:21:14.818 INFO 3872 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2017-07-25 23:21:14.818 INFO 3872 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)

下面是我的项目结构:

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-26 13:09:33

正如@Afridi所建议的,异常甚至在到达控制器之前就会发生,所以它必须在过滤器链中处理。我建议做以下几点:

代码语言:javascript
运行
复制
public class AccessDeniedExceptionFilter extends OncePerRequestFilter {

    @Override
    public void doFilterInternal(HttpServletRequest req, HttpServletResponse res, 
                                FilterChain fc) throws ServletException, IOException {
        try {
            fc.doFilter(request, response);
        } catch (AccessDeniedException e) {
         // log error if needed here then redirect
     RequestDispatcher requestDispatcher = 
             getServletContext().getRequestDispatcher(redirecturl);
     requestDispatcher.forward(request, response);

    }
}

将此筛选器添加到筛选器链

代码语言:javascript
运行
复制
protected void configure(HttpSecurity http) throws Exception {
http
....
.addFilterAfter(httpClientFilter(), AccessDeniedExceptionFilter.class)
票数 0
EN

Stack Overflow用户

发布于 2018-12-28 22:31:10

我使用一个自定义类来扩展带有一些注释的ResponseEntityExceptionHandler

您只需要创建一个如下所示的类:

代码语言:javascript
运行
复制
@ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(AccessDeniedException.class)
    public final ResponseEntity<ErrorMessage> handleAccessDeniedException(AccessDeniedException ex, WebRequest request) {
        ErrorMessage errorDetails = new ErrorMessage(new Date(), ex.getMessage(), request.getDescription(false));
        return new ResponseEntity<>(errorDetails, HttpStatus.FORBIDDEN);
    }

}

在这种情况下,答案将类似于:

代码语言:javascript
运行
复制
{
    "timestamp": "2018-12-28T14:25:23.213+0000",
    "message": "Access is denied",
    "details": "uri=/user/list"
}
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45317638

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档