美文网首页
基于HandlerInterceptor权限统一拦截

基于HandlerInterceptor权限统一拦截

作者: 离别刀 | 来源:发表于2018-05-25 10:21 被阅读0次
    80608151328.png

    HandlerInterceptor基于JDK动态代理实现request的拦截。接口共有3个方法:

    public interface HandlerInterceptor {
        boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
        void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception;
        void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception;
    }
    

    1.preHandle,在访问真正的request之前的预处理,只有该方法返回true时候,请求才能到达controller。因此我们可以在此对request做一定处理。比如判断用户是否有权限访问该接口、对接口访问做日志记录等。

    2.postHandle,只有当preHandle返回true之后,才能执行该接口,该接口是在请求完成之后,DispatcherServlet进行视图返回渲染之前调用。一般在此接口我们可以操作ModelAndView,在实际当中我们可以在此处设置静态文件的版本号,jsp中的静态文件引用只需要引用改变量,就可以实现动态刷新静态文件。

    3.afterCompletion,该接口也是只有当preHandle返回true之后才会执行,它是在DispatcherServlet渲染完模板之后才会调用。一般在次方法中清除缓存变量等。比如我们想实现一个用户请求过来,验证完权限之后,我们在preHandle中将用户信息放到ThreadLocal中,后面的controller,service就直接可以从该接ThreadLocal中获取用户信息。但当该请求完成之后,需要在afterCompletion中清理该ThreadLocal变量。

    下面示例主要是实现用户权限的拦截,比较简单,该示例中用到了自定义注解,对于controller中加了注解的接口,在拦截器可以根据注解设置不同的拦截;如下面设置了Permition注解 124100740.png

    ,表示该接口开放。

    拦截器

    @Component
    public class AuthInterceptor implements HandlerInterceptor {
        @Value("${session.timeout}")
        private long EXPIRE_TIME;//用户session缓存时间
        @Autowired
        private RedisOperations redisOperations;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if (handler == null || handler instanceof ResourceHttpRequestHandler) {
                return true;
            }
            if(handler instanceof HandlerMethod){
                String name= ((HandlerMethod) handler).getMethod().getName();
                if(("errorHtml".equalsIgnoreCase(name))){
                    throw new PageException("the url: "+request.getRequestURL()+" not exists.");
                }
            }
            return verify(request,handler);
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            UserThreadLocal.clear();
        }
    
        private boolean verify(HttpServletRequest request, Object handler){
            Permition permition = verifyPermit(handler);
            if(permition!=null && permition.oriented()==Permit.All){
                return true;
            }
            return verifyUser(request);
        }
    
        private boolean verifyUser(HttpServletRequest request){
            //假设用户的身份信息是从header上传,从header中取出身份信息
            String headerKey= request.getHeader(UserKeyUtils.IDENTITY);
            if(StringUtils.isEmpty(headerKey)){
                throw new BusinessException(0,"no authority.");
            }
            //从身份信息中提取出用户key
            String userRedisKey= UserKeyUtils.getUserRedisKey(headerKey);
            //从缓存中获取用户信息
            User user= redisOperations.getVal(userRedisKey,User.class);
            if(user==null){
                throw new BusinessException(-1,"token invalidate or expired.");
            }
            if(StringUtils.isEmpty(user.schoolId)){
                throw new BusinessException("schoolId not empty.");
            }
            user.token = headerKey;
            //验证完成之后会将用户信息存入redis
            redisOperations.putVal(userRedisKey,user,EXPIRE_TIME);
            //用户信息存入ThreadLocal
            UserThreadLocal.set(user);
            return true;
        }
        
        //权限验证,可以在此处扩展更复杂的权限控制,比如基于url的资源拦截。
        private Permition verifyPermit(Object handler) {
            Permition permit= null;
            if (handler instanceof HandlerMethod){
                 permit = ((HandlerMethod) handler).getMethod().getAnnotation(Permition.class);
                if(permit == null){
                    permit = ((HandlerMethod) handler).getBeanType().getAnnotation(Permition.class);
                }
            }
            return permit;
        }
    }
    

    UserThreadLocal

    public class UserThreadLocal {
        private static final ThreadLocal<User> userThreadLocal= new ThreadLocal<>();
        public static User get(){
           return userThreadLocal.get();
        }
        public static void set(User user){
            userThreadLocal.set(user);
        }
        public static void clear(){
            userThreadLocal.remove();
        }
    }
    

    相关文章

      网友评论

          本文标题:基于HandlerInterceptor权限统一拦截

          本文链接:https://www.haomeiwen.com/subject/jllyjftx.html