HandlerInterceptor 实现拦截器实现自定义鉴权详解

HandlerInterceptor 详解

HandlerInterceptor 允许定制 handler 处理器执行链的工作流接口。我们可以自定义拦截器用于拦截 handlers 处理器(你可以理解为 controller 层的接口),从而可以添加一些共同的重复性的处理行为(例如接口鉴权,接口日志记录,性能监控等),而不用修改每一个 handler 的实现。

注意,此基于 SpringBoot 2.3.12.RELEASE 版本讲解。

HandlerInterceptor 接口只有三个默认空实现方法,在低版本中这三个方法不是默认方法,而是抽象方法。

 public interface HandlerInterceptor {
 ​
     default boolean preHandle(HttpServletRequest request, HttpServletResponse response,                 Object handler) throws Exception {
         return true;
     }
 ​
     default void postHandle(HttpServletRequest request, HttpServletResponse response,                 Object handler, @Nullable ModelAndView modelAndView) throws Exception {
     }
 ​
     default void afterCompletion(HttpServletRequest request, HttpServletResponse response,             Object handler, @Nullable Exception ex) throws Exception {
     }
 }

这三个方法的执行顺序图如下:

preHandle

preHandle 前置处理,拦截一个处理器(handler)的执行,preHandle 方法会在 HandlerMapping 确定一个适当的处理器对象之后,但在 HandlerAdapter 调用处理器之前被调用。可以简单理解为 controller 接口被调用之前执行。

Intercepter 是链式的,就是一个接着一个执行。如果此方法返回 true,则会执行下一个拦截器或者直接执行处理器。如果此方法返回 false 或者抛出异常则终止执行链,也不再调用处理器。

注意,此方法如果不返回 true,那么 postHandle 和 afterCompletion 不会被执行。

那这个方法有什么用呢?其实可以做一些接口被调用前的预处理,例如用户权限校验。

 package com.chenpi;
 ​
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 ​
 import org.springframework.lang.Nullable;
 import org.springframework.stereotype.Component;
 import org.springframework.web.method.HandlerMethod;
 import org.springframework.web.servlet.HandlerInterceptor;
 ​
 /**
  * @Description 用户权限验证拦截
  * @Author 陈皮
  * @Date 2021/6/27
  * @Version 1.0
  */
 @Component
 public class UserPermissionInterceptor implements HandlerInterceptor {
 ​
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
             Object handler) {
 ​
         if (handler instanceof HandlerMethod) {
 ​
             HandlerMethod handlerMethod = (HandlerMethod) handler;
 ​
             // 获取用户权限校验注解
             UserAuthenticate userAuthenticate =
                     handlerMethod.getMethod().getAnnotation(UserAuthenticate.class);
             if (null == userAuthenticate) {
                 userAuthenticate = handlerMethod.getMethod().getDeclaringClass()
                         .getAnnotation(UserAuthenticate.class);
             }
             if (userAuthenticate != null && userAuthenticate.permission()) {
                 // 验证用户信息
                 UserContext userContext = userContextManager.getUserContext(request);
                 if (null == userContext) {
                     return false;
                 }
             }
         }
         return true;
     }
 }

postHandle

postHandle 后置处理,会在 HandlerAdapter 调用处理器之后,但在 DispatcherServlet 渲染视图之前被调用。可以在此对 ModelAndView 做一些额外的处理。可以简单理解为 controller 接口被调用之后执行。

注意,此方法在执行链中的执行顺序是倒着执行的,即先声明的拦截器后执行。

afterCompletion

afterCompletion 完成之后,在请求处理完之后被执行,也就是渲染完视图之后。一般用于做一些资源的清理工作,配合 preHandle 计算接口执行时间等。

注意,和 postHandle 一样,此方法在执行链中的执行顺序也是倒着执行的,即先声明的拦截器后执行。

 @Override
 public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                             Object handler, @Nullable Exception ex) {
     // 请求完后,清除当前线程的用户信息
     UserContextHolder.removeUserContext();
 }

注册拦截器

注意,我们自定义的拦截器要通过 WebMvcConfigurer 的实现类进行注册,才能生效。

 package com.yzj.ehr.common.config;
 ​
 import com.yzj.ehr.common.context.UserContextResolver;
 import org.springframework.stereotype.Component;
 import org.springframework.web.method.support.HandlerMethodArgumentResolver;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 ​
 import com.yzj.ehr.common.interceptor.UserPermissionInterceptor;
 ​
 /**
  * @Description 注册拦截器
  * @Author 陈皮
  * @Date 2021/6/27
  * @Version 1.0
  */
 @Component
 public class WebAppConfigurer implements WebMvcConfigurer {
 ​
     private UserPermissionInterceptor userPermissionInterceptor;
 ​
     public WebAppConfigurer(final UserPermissionInterceptor userPermissionInterceptor) {
         this.userPermissionInterceptor = userPermissionInterceptor;
     }
 ​
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         // 匹配所有接口,排除/base/test接口
         registry.addInterceptor(userPermissionInterceptor).addPathPatterns("/**")
                 .excludePathPatterns("/base/test");
     }
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值