SpringSecurity 的无权访问异常理器 AccessDeniedHandler 与统一异常处理器 DefaultHandlerExceptionResolver 冲突

2021-04-21 13:58:16 +08:00
 devswork

项目使用 SpringSecurity 进行 API 权限控制,在项目中实现了 AccessDeniedHandler 接口用于被拒绝时的异常处理:

@Slf4j
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        log.info("AccessDeniedHandler 异常....."); //打印被拒绝日志
        httpServletResponse.setContentType("text/json;charset=utf-8");
        httpServletResponse.getWriter().write(JSON.toJSONString(ResultGenerator.noPermission()));
    }

}

并且在 WebSecurityConfigurerAdapter 的 http 配置中配置了异常处理:

@Bean
public AccessDeniedHandler getAccessDeniedHandler() {
	return new MyAccessDeniedHandler();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
	// ....
	
	//异常处理
	http.exceptionHandling().accessDeniedHandler(getAccessDeniedHandler());
	
	// ...
}

项目中还是用了统一异常处理器 DefaultHandlerExceptionResolver:

@Slf4j
@Component
@ControllerAdvice
public class MyGlobalExceptionHandler extends DefaultHandlerExceptionResolver {

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public R defaultErrorHandler(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
		
	e.printStackTrace(); //打印堆栈
        log.info("DefaultHandlerExceptionResolver 统一异常处理器...");//打印异常日志
		
    }
}

问题来了,当无权访问时,并不是执行 MyAccessDeniedHandler (尽管它已经在 SpringSecurity 中已经注册异常处理器),这个异常始终会在 MyGlobalExceptionHandler 中处理,打印了堆栈信息和异常日志:

2021-04-21 13:52:30.226  INFO 32684 --- [io-18000-exec-2] c.d.m.s.TokenAuthenticationFilter        : TokenAuthenticationFilter...token = d72b29cbaa074cba99377cec73999575
2021-04-21 13:52:30.235  INFO 32684 --- [io-18000-exec-2] c.d.mp.support.MyGlobalExceptionHandler  : DefaultHandlerExceptionResolver 统一异常处理器...
2021-04-21 13:52:30.235  INFO 32684 --- [io-18000-exec-2] c.d.mp.support.MyGlobalExceptionHandler  : 无权限访问...http://127.0.0.1:18000/test/hello  R(code=403, data=null, message=没有权限访问, time=1618984350235)
org.springframework.security.access.AccessDeniedException: 不允许访问
	at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73)
	at org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:238)
	at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:208)
	at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:58)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
	at com.dkdy.mp.controller.business.TestController$$EnhancerBySpringCGLIB$$fe1a52b5.hello(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	..............

如何让无权访问的异常被 MyAccessDeniedHandler 捕获处理,而不是让统一异常处理器来处理 SpringSecurity 的无权访问异常呢?

538 次点击
所在节点    Java
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/772172

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX