
项目使用 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="); 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 的无权访问异常呢?